piegy 2.1.8__cp37-cp37m-win32.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- piegy/C_core/Makefile +97 -0
- piegy/C_core/model.c +108 -0
- piegy/C_core/model.h +54 -0
- piegy/C_core/patch.c +43 -0
- piegy/C_core/patch.h +43 -0
- piegy/C_core/piegyc.cp37-win32.pyd +0 -0
- piegy/C_core/piegyc.h +49 -0
- piegy/C_core/runner.c +61 -0
- piegy/C_core/sim_funcs.c +561 -0
- piegy/C_core/sim_funcs.h +547 -0
- piegy/__init__.py +57 -0
- piegy/__version__.py +33 -0
- piegy/analysis.py +222 -0
- piegy/build_info.py +12 -0
- piegy/data_tools.py +127 -0
- piegy/figures.py +491 -0
- piegy/find_C.py +17 -0
- piegy/simulation.py +509 -0
- piegy/simulation_py.py +816 -0
- piegy/test_var.py +583 -0
- piegy/tools/__init__.py +15 -0
- piegy/tools/figure_tools.py +238 -0
- piegy/tools/file_tools.py +29 -0
- piegy/videos.py +303 -0
- piegy-2.1.8.dist-info/LICENSE.txt +28 -0
- piegy-2.1.8.dist-info/METADATA +112 -0
- piegy-2.1.8.dist-info/RECORD +29 -0
- piegy-2.1.8.dist-info/WHEEL +5 -0
- piegy-2.1.8.dist-info/top_level.txt +1 -0
piegy/C_core/sim_funcs.c
ADDED
@@ -0,0 +1,561 @@
|
|
1
|
+
/**
|
2
|
+
* This .c defines the simulation functions in piegy.simulation
|
3
|
+
*/
|
4
|
+
|
5
|
+
#include <stdbool.h>
|
6
|
+
#include <time.h>
|
7
|
+
|
8
|
+
#include "sim_funcs.h"
|
9
|
+
#include "patch.h"
|
10
|
+
#include "model.h"
|
11
|
+
|
12
|
+
|
13
|
+
|
14
|
+
static void find_nb_zero_flux(size_t* restrict nb, size_t i, size_t j, size_t N, size_t M, size_t NM) {
|
15
|
+
// Up
|
16
|
+
if (i != 0) {
|
17
|
+
nb[0] = (i - 1) * M + j;
|
18
|
+
} else {
|
19
|
+
nb[0] = NM; // N * M for nb doesn't exist
|
20
|
+
}
|
21
|
+
|
22
|
+
// Down
|
23
|
+
if (i != N - 1) {
|
24
|
+
nb[1] = (i + 1) * M + j;
|
25
|
+
} else {
|
26
|
+
nb[1] = NM;
|
27
|
+
}
|
28
|
+
|
29
|
+
// Left
|
30
|
+
if (j != 0) {
|
31
|
+
nb[2] = i * M + j - 1;
|
32
|
+
} else {
|
33
|
+
nb[2] = NM;
|
34
|
+
}
|
35
|
+
|
36
|
+
// Right
|
37
|
+
if (j != M - 1) {
|
38
|
+
nb[3] = i * M + j + 1;
|
39
|
+
} else {
|
40
|
+
nb[3] = NM;
|
41
|
+
}
|
42
|
+
}
|
43
|
+
|
44
|
+
|
45
|
+
static void find_nb_periodical(size_t* restrict nb, size_t i, size_t j, size_t N, size_t M, size_t NM) {
|
46
|
+
// up
|
47
|
+
if (N != 1) {
|
48
|
+
nb[0] = (i != 0) ? (i - 1) * M + j : (N - 1) * M + j;
|
49
|
+
} else {
|
50
|
+
nb[0] = NM;
|
51
|
+
}
|
52
|
+
|
53
|
+
// down
|
54
|
+
if (N != 1) {
|
55
|
+
nb[1] = (i != N - 1) ? (i + 1) * M + j : j;
|
56
|
+
} else {
|
57
|
+
nb[1] = NM;
|
58
|
+
}
|
59
|
+
|
60
|
+
// We explicitly asked for M > 1
|
61
|
+
// left
|
62
|
+
nb[2] = (j != 0) ? i * M + j - 1 : i * M + M - 1;
|
63
|
+
|
64
|
+
// right
|
65
|
+
nb[3] = (j != M - 1) ? i * M + j + 1 : i * M;
|
66
|
+
}
|
67
|
+
|
68
|
+
|
69
|
+
|
70
|
+
// single_init function: initializes world, runs 1 event, returns updated variables
|
71
|
+
static double single_init(const model_t* mod, patch_t* world, size_t* nb_indices,
|
72
|
+
double* patch_rates, double* sum_rates_by_row, double* sum_rates_p, signal_t* sig_p, patch_picked_t* picked_p) {
|
73
|
+
|
74
|
+
size_t N = mod->N;
|
75
|
+
size_t M = mod->M;
|
76
|
+
size_t NM = N * M;
|
77
|
+
size_t max_record = mod->max_record;
|
78
|
+
size_t ij = 0; // used to track index i * M + j in double for loops
|
79
|
+
|
80
|
+
// init world
|
81
|
+
for (size_t i = 0; i < N; i++) {
|
82
|
+
for (size_t j = 0; j < M; j++) {
|
83
|
+
patch_init(&world[ij], mod->I[ij * 2], mod->I[ij * 2 + 1], i, j);
|
84
|
+
ij++;
|
85
|
+
}
|
86
|
+
}
|
87
|
+
|
88
|
+
// init nb_indices
|
89
|
+
ij = 0;
|
90
|
+
if (mod->boundary) {
|
91
|
+
for (size_t i = 0; i < N; i++) {
|
92
|
+
for (size_t j = 0; j < M; j++) {
|
93
|
+
find_nb_zero_flux(&nb_indices[ij * 4], i, j, N, M, NM);
|
94
|
+
ij++;
|
95
|
+
}
|
96
|
+
}
|
97
|
+
} else {
|
98
|
+
for (size_t i = 0; i < N; i++) {
|
99
|
+
for (size_t j = 0; j < M; j++) {
|
100
|
+
find_nb_periodical(&nb_indices[ij * 4], i, j, N, M, NM);
|
101
|
+
ij++;
|
102
|
+
}
|
103
|
+
}
|
104
|
+
}
|
105
|
+
|
106
|
+
|
107
|
+
// set nb pointers for patches
|
108
|
+
ij = 0;
|
109
|
+
for (size_t i = 0; i < N; i++) {
|
110
|
+
for (size_t j = 0; j < M; j++) {
|
111
|
+
set_nb(world, &nb_indices[ij * 4], ij, NM);
|
112
|
+
ij++;
|
113
|
+
}
|
114
|
+
}
|
115
|
+
|
116
|
+
//////// Begin Running ////////
|
117
|
+
|
118
|
+
// init payoff & natural death rates
|
119
|
+
ij = 0;
|
120
|
+
for (size_t i = 0; i < N; i++) {
|
121
|
+
for (size_t j = 0; j < M; j++) {
|
122
|
+
update_pi_k(&world[ij], &(mod->X[ij * 4]), &(mod->P[ij * 6 + 4]));
|
123
|
+
ij++;
|
124
|
+
}
|
125
|
+
}
|
126
|
+
|
127
|
+
// init migration rates & store patch rates
|
128
|
+
ij = 0;
|
129
|
+
for (size_t i = 0; i < N; i++) {
|
130
|
+
for (size_t j = 0; j < M; j++) {
|
131
|
+
update_mig_all(&world[ij], &(mod->P[ij * 6])); // init mig rates for all 4 directions
|
132
|
+
double ij_rates = world[ij].sum_pi_death_rates + world[ij].sum_mig_rates;
|
133
|
+
patch_rates[ij] = ij_rates;
|
134
|
+
sum_rates_by_row[i] += ij_rates;
|
135
|
+
*sum_rates_p = *sum_rates_p + ij_rates; // can't do *sum_rates_p += ij_rates
|
136
|
+
ij++;
|
137
|
+
}
|
138
|
+
}
|
139
|
+
|
140
|
+
// pick the first random event
|
141
|
+
double expected_sum = random01() * *sum_rates_p;
|
142
|
+
find_patch(picked_p, expected_sum, patch_rates, sum_rates_by_row, *sum_rates_p, N, M);
|
143
|
+
size_t picked_idx = picked_p->i * M + picked_p->j;
|
144
|
+
size_t e0 = find_event(&world[picked_idx], expected_sum - picked_p->current_sum);
|
145
|
+
|
146
|
+
// make signal
|
147
|
+
if (mod->boundary) {
|
148
|
+
make_signal_zero_flux(picked_p->i, picked_p->j, e0, sig_p);
|
149
|
+
} else {
|
150
|
+
make_signal_periodical(N, M, picked_p->i, picked_p->j, e0, sig_p);
|
151
|
+
}
|
152
|
+
sig_p->ij1 = sig_p->i1 * M + sig_p->j1;
|
153
|
+
sig_p->ij2 = sig_p->i2 * M + sig_p->j2;
|
154
|
+
|
155
|
+
// update patch based on signal
|
156
|
+
change_popu(&world[sig_p->ij1], sig_p->e1);
|
157
|
+
if (!sig_p->only_first) {
|
158
|
+
change_popu(&world[sig_p->ij2], sig_p->e2);
|
159
|
+
}
|
160
|
+
|
161
|
+
// time increment
|
162
|
+
double time = (1.0 / *sum_rates_p) * log(1.0 / random01());
|
163
|
+
|
164
|
+
if (time > mod->maxtime) {
|
165
|
+
// maxtime too small
|
166
|
+
return -1;
|
167
|
+
}
|
168
|
+
|
169
|
+
// store data
|
170
|
+
if (time > mod->record_itv) {
|
171
|
+
size_t recod_idx = (size_t) (time / mod->record_itv);
|
172
|
+
ij = 0;
|
173
|
+
for (size_t i = 0; i < N; i++) {
|
174
|
+
for (size_t j = 0; j < M; j++) {
|
175
|
+
for (size_t k = 0; k < recod_idx; k++) {
|
176
|
+
mod->U1d[ij * max_record + k] += world[ij].U;
|
177
|
+
mod->V1d[ij * max_record + k] += world[ij].V;
|
178
|
+
mod->Upi_1d[ij * max_record + k] += world[ij].U_pi;
|
179
|
+
mod->Vpi_1d[ij * max_record + k] += world[ij].V_pi;
|
180
|
+
}
|
181
|
+
ij++;
|
182
|
+
}
|
183
|
+
}
|
184
|
+
}
|
185
|
+
|
186
|
+
return time;
|
187
|
+
}
|
188
|
+
|
189
|
+
|
190
|
+
|
191
|
+
static void single_test(model_t* restrict mod, uint32_t update_sum_frequency, uint32_t* result, char* message) {
|
192
|
+
// bring some dimensions to the front
|
193
|
+
size_t N = mod->N;
|
194
|
+
size_t M = mod->M;
|
195
|
+
size_t NM = N * M;
|
196
|
+
double maxtime = mod->maxtime;
|
197
|
+
size_t max_record = mod->max_record;
|
198
|
+
double record_itv = mod->record_itv;
|
199
|
+
bool boundary = mod->boundary;
|
200
|
+
|
201
|
+
double one_time = maxtime / (double)(update_sum_frequency > 100 ? update_sum_frequency : 100);
|
202
|
+
double one_progress = 0.0;
|
203
|
+
|
204
|
+
if (mod->print_pct != -1) {
|
205
|
+
one_progress = maxtime * mod->print_pct / 100.0;
|
206
|
+
fprintf(stdout, "\r ");
|
207
|
+
fprintf(stdout, "\r%s: 0 %%", message);
|
208
|
+
fflush(stdout);
|
209
|
+
} else {
|
210
|
+
one_progress = 2.0 * maxtime;
|
211
|
+
}
|
212
|
+
|
213
|
+
double one_update_sum = maxtime / (double) (update_sum_frequency + 1);
|
214
|
+
|
215
|
+
double current_time = one_time;
|
216
|
+
double current_progress = one_progress;
|
217
|
+
double current_update_sum = one_update_sum;
|
218
|
+
|
219
|
+
// Initialize simulation
|
220
|
+
patch_t* world = (patch_t*) calloc(NM * SIZEOF_PATCH_T, sizeof(size_t));
|
221
|
+
size_t* nb_indices = (size_t*) calloc(NM * 4, sizeof(size_t));
|
222
|
+
|
223
|
+
double* patch_rates = (double*) calloc(NM, sizeof(double));
|
224
|
+
double* sum_rates_by_row = (double*) calloc(N, sizeof(double));
|
225
|
+
double sum_rates = 0.0;
|
226
|
+
|
227
|
+
signal_t signal;
|
228
|
+
patch_picked_t picked;
|
229
|
+
|
230
|
+
double time = single_init(mod, world, nb_indices, patch_rates, sum_rates_by_row, &sum_rates, &signal, &picked);
|
231
|
+
if (time == -1) {
|
232
|
+
// time too small
|
233
|
+
*result = SMALL_MAXTIME;
|
234
|
+
single_test_free(world, nb_indices, patch_rates, sum_rates_by_row);
|
235
|
+
world = NULL;
|
236
|
+
nb_indices = NULL;
|
237
|
+
patch_rates = NULL;
|
238
|
+
sum_rates_by_row = NULL;
|
239
|
+
return;
|
240
|
+
}
|
241
|
+
size_t record_index = time / mod->record_itv;
|
242
|
+
double record_time = time - record_index * record_itv;
|
243
|
+
|
244
|
+
|
245
|
+
while (time < maxtime) {
|
246
|
+
|
247
|
+
// Print progress and update sums if needed
|
248
|
+
if (time > current_time) {
|
249
|
+
current_time += one_time;
|
250
|
+
if (time > current_progress) {
|
251
|
+
uint8_t curr_prog = (uint8_t)(time * 100 / maxtime);
|
252
|
+
if (curr_prog < 10) {
|
253
|
+
fprintf(stdout, "\r%s: %d %%", message, (int)(time * 100 / maxtime));
|
254
|
+
} else {
|
255
|
+
fprintf(stdout, "\r%s: %d%%", message, (int)(time * 100 / maxtime));
|
256
|
+
}
|
257
|
+
fflush(stdout);
|
258
|
+
//fflush(stdout); // Make sure it prints immediately
|
259
|
+
current_progress += one_progress;
|
260
|
+
}
|
261
|
+
if (time > current_update_sum) {
|
262
|
+
current_update_sum += one_update_sum;
|
263
|
+
|
264
|
+
// recalculate sum
|
265
|
+
size_t ij = 0;
|
266
|
+
for (size_t i = 0; i < N; i++) {
|
267
|
+
for (size_t j = 0; j < M; j++) {
|
268
|
+
world[ij].sum_U_weight = 0;
|
269
|
+
world[ij].sum_V_weight = 0;
|
270
|
+
for (size_t k = 0; k < 4; k++) {
|
271
|
+
world[ij].sum_U_weight += world[ij].U_weight[k];
|
272
|
+
world[ij].sum_V_weight += world[ij].V_weight[k];
|
273
|
+
}
|
274
|
+
}
|
275
|
+
}
|
276
|
+
ij = 0;
|
277
|
+
for (size_t i = 0; i < N; i++) {
|
278
|
+
sum_rates_by_row[i] = 0;
|
279
|
+
for (size_t j = 0; j < M; j++) {
|
280
|
+
sum_rates_by_row[i] += patch_rates[ij];
|
281
|
+
ij++;
|
282
|
+
}
|
283
|
+
}
|
284
|
+
sum_rates = 0;
|
285
|
+
for (size_t i = 0; i < N; i++) {
|
286
|
+
sum_rates += sum_rates_by_row[i];
|
287
|
+
}
|
288
|
+
}
|
289
|
+
// check overflow
|
290
|
+
size_t ij = 0;
|
291
|
+
for (size_t i = 0; i < N; i++) {
|
292
|
+
for (size_t j = 0; j < M; j++) {
|
293
|
+
if ((mod->P[ij * 6 + 2] * world[ij].U_pi > EXP_OVERFLOW_BOUND)
|
294
|
+
|| (mod->P[ij * 6 + 3] * world[ij].V_pi > EXP_OVERFLOW_BOUND)) {
|
295
|
+
fprintf(stdout, "\nError: overflow at time about %f, patch (%zu, %zu). Simulation stopped.\n", time, i, j);
|
296
|
+
fflush(stdout);
|
297
|
+
*result = OVERFLOW;
|
298
|
+
single_test_free(world, nb_indices, patch_rates, sum_rates_by_row);
|
299
|
+
world = NULL;
|
300
|
+
nb_indices = NULL;
|
301
|
+
patch_rates = NULL;
|
302
|
+
sum_rates_by_row = NULL;
|
303
|
+
return;
|
304
|
+
}
|
305
|
+
ij += 1;
|
306
|
+
}
|
307
|
+
}
|
308
|
+
}
|
309
|
+
|
310
|
+
// update last-changed patches
|
311
|
+
// subtract old rates first, then update patch, then add new rates
|
312
|
+
// and split into cases whether there are two or one last-changed patches (because need to update all payoffs first and then mig rates)
|
313
|
+
size_t si1 = signal.i1;
|
314
|
+
size_t si2 = signal.i2;
|
315
|
+
size_t sij1 = signal.ij1;
|
316
|
+
size_t sij2 = signal.ij2;
|
317
|
+
bool only_first = signal.only_first;
|
318
|
+
if (only_first) {
|
319
|
+
// if only one
|
320
|
+
double picked_rate = world[sij1].sum_pi_death_rates + world[sij1].sum_mig_rates;
|
321
|
+
sum_rates_by_row[si1] -= picked_rate;
|
322
|
+
sum_rates -= picked_rate;
|
323
|
+
|
324
|
+
update_pi_k(&world[sij1], &(mod->X[sij1 * 4]), &(mod->P[sij1 * 6 + 4]));
|
325
|
+
update_mig_all(&world[sij1], &(mod->P[sij1 * 6]));
|
326
|
+
|
327
|
+
picked_rate = world[sij1].sum_pi_death_rates + world[sij1].sum_mig_rates;
|
328
|
+
patch_rates[sij1] = picked_rate;
|
329
|
+
sum_rates_by_row[si1] += picked_rate;
|
330
|
+
sum_rates += picked_rate;
|
331
|
+
} else {
|
332
|
+
// two
|
333
|
+
double picked_rate1 = world[sij1].sum_pi_death_rates + world[sij1].sum_mig_rates;
|
334
|
+
double picked_rate2 = world[sij2].sum_pi_death_rates + world[sij2].sum_mig_rates;
|
335
|
+
sum_rates_by_row[si1] -= picked_rate1;
|
336
|
+
sum_rates_by_row[si2] -= picked_rate2;
|
337
|
+
sum_rates -= picked_rate1;
|
338
|
+
sum_rates -= picked_rate2;
|
339
|
+
|
340
|
+
update_pi_k(&world[sij1], &(mod->X[sij1 * 4]), &(mod->P[sij1 * 6 + 4])); // update both patches' payoffs first
|
341
|
+
update_pi_k(&world[sij2], &(mod->X[sij2 * 4]), &(mod->P[sij2 * 6 + 4]));
|
342
|
+
update_mig_all(&world[sij1], &(mod->P[sij1 * 6])); // and then mig rates
|
343
|
+
update_mig_all(&world[sij2], &(mod->P[sij2 * 6]));
|
344
|
+
|
345
|
+
picked_rate1 = world[sij1].sum_pi_death_rates + world[sij1].sum_mig_rates;
|
346
|
+
picked_rate2 = world[sij2].sum_pi_death_rates + world[sij2].sum_mig_rates;
|
347
|
+
|
348
|
+
patch_rates[sij1] = picked_rate1;
|
349
|
+
patch_rates[sij2] = picked_rate2;
|
350
|
+
sum_rates_by_row[si1] += picked_rate1;
|
351
|
+
sum_rates_by_row[si2] += picked_rate2;
|
352
|
+
sum_rates += picked_rate1;
|
353
|
+
sum_rates += picked_rate2;
|
354
|
+
}
|
355
|
+
|
356
|
+
// update neighbors of last-changed patches
|
357
|
+
if (only_first) {
|
358
|
+
for (uint8_t k = 0; k < 4; k++) {
|
359
|
+
size_t nb_idx = nb_indices[sij1 * 4 + k];
|
360
|
+
if (nb_idx == NM) { continue; } // invalid neighbor
|
361
|
+
// all neighbors, as long as exists, need to change
|
362
|
+
update_mig_all(&world[nb_idx], &(mod->P[nb_idx * 6]));
|
363
|
+
// sum_mig_rate is not changed
|
364
|
+
}
|
365
|
+
} else {
|
366
|
+
// the first patch
|
367
|
+
for (uint8_t k = 0; k < 4; k++) {
|
368
|
+
size_t nb_idx = nb_indices[sij1 * 4 + k];
|
369
|
+
if (nb_idx == NM) { continue; }
|
370
|
+
if (nb_need_change(nb_idx, sij1, sij2)) {
|
371
|
+
update_mig_all(&world[nb_idx], &(mod->P[nb_idx * 6]));
|
372
|
+
}
|
373
|
+
}
|
374
|
+
// the second patch
|
375
|
+
for (uint8_t k = 0; k < 4; k++) {
|
376
|
+
size_t nb_idx = nb_indices[sij2 * 4 + k];
|
377
|
+
if (nb_idx == NM) { continue; }
|
378
|
+
if (nb_need_change(nb_idx, sij1, sij2)) {
|
379
|
+
update_mig_all(&world[nb_idx], &(mod->P[nb_idx * 6]));
|
380
|
+
}
|
381
|
+
}
|
382
|
+
}
|
383
|
+
|
384
|
+
|
385
|
+
// pick a random event
|
386
|
+
double expected_sum = random01() * sum_rates;
|
387
|
+
find_patch(&picked, expected_sum, patch_rates, sum_rates_by_row, sum_rates, N, M);
|
388
|
+
size_t picked_idx = picked.i * M + picked.j;
|
389
|
+
uint8_t e0 = find_event(&world[picked_idx], expected_sum - picked.current_sum);
|
390
|
+
|
391
|
+
// make signal
|
392
|
+
if (boundary) {
|
393
|
+
make_signal_zero_flux(picked.i, picked.j, e0, &signal);
|
394
|
+
} else {
|
395
|
+
make_signal_periodical(N, M, picked.i, picked.j, e0, &signal);
|
396
|
+
}
|
397
|
+
signal.ij1 = signal.i1 * M + signal.j1;
|
398
|
+
signal.ij2 = signal.i2 * M + signal.j2;
|
399
|
+
|
400
|
+
// let the event happenn
|
401
|
+
change_popu(&world[signal.ij1], signal.e1);
|
402
|
+
if (!signal.only_first) {
|
403
|
+
change_popu(&world[signal.ij2], signal.e2);
|
404
|
+
}
|
405
|
+
|
406
|
+
// increase time
|
407
|
+
double dt = (1.0 / sum_rates) * log(1.0 / random01());
|
408
|
+
time += dt;
|
409
|
+
record_time += dt;
|
410
|
+
|
411
|
+
// record data
|
412
|
+
if (time < maxtime) {
|
413
|
+
if (record_time > record_itv) {
|
414
|
+
size_t multi_records = record_time / record_itv;
|
415
|
+
record_time -= multi_records * record_itv;
|
416
|
+
size_t upper = record_index + multi_records;
|
417
|
+
|
418
|
+
size_t ij = 0;
|
419
|
+
for (size_t i = 0; i < N; i++) {
|
420
|
+
for (size_t j = 0; j < M; j++) {
|
421
|
+
for (size_t k = record_index; k < upper; k++) {
|
422
|
+
mod->U1d[ij * max_record + k] += world[ij].U;
|
423
|
+
mod->V1d[ij * max_record + k] += world[ij].V;
|
424
|
+
mod->Upi_1d[ij * max_record + k] += world[ij].U_pi;
|
425
|
+
mod->Vpi_1d[ij * max_record + k] += world[ij].V_pi;
|
426
|
+
}
|
427
|
+
ij++;
|
428
|
+
}
|
429
|
+
}
|
430
|
+
record_index += multi_records;
|
431
|
+
}
|
432
|
+
|
433
|
+
} else {
|
434
|
+
// if already exceeds maxtime
|
435
|
+
size_t ij = 0;
|
436
|
+
for (size_t i = 0; i < N; i++) {
|
437
|
+
for (size_t j = 0; j < M; j++) {
|
438
|
+
for (size_t k = record_index; k < max_record; k++) {
|
439
|
+
mod->U1d[ij * max_record + k] += world[ij].U;
|
440
|
+
mod->V1d[ij * max_record + k] += world[ij].V;
|
441
|
+
mod->Upi_1d[ij * max_record + k] += world[ij].U_pi;
|
442
|
+
mod->Vpi_1d[ij * max_record + k] += world[ij].V_pi;
|
443
|
+
}
|
444
|
+
ij++;
|
445
|
+
}
|
446
|
+
}
|
447
|
+
}
|
448
|
+
}
|
449
|
+
|
450
|
+
//////// End of while loop ////////
|
451
|
+
|
452
|
+
/*if (mod->print_pct != -1) {
|
453
|
+
fprintf(stdout, "\r%s: 100%%", message);
|
454
|
+
fflush(stdout);
|
455
|
+
}*/
|
456
|
+
|
457
|
+
single_test_free(world, nb_indices, patch_rates, sum_rates_by_row);
|
458
|
+
world = NULL;
|
459
|
+
nb_indices = NULL;
|
460
|
+
patch_rates = NULL;
|
461
|
+
sum_rates_by_row = NULL;
|
462
|
+
|
463
|
+
*result = SUCCESS;
|
464
|
+
}
|
465
|
+
|
466
|
+
|
467
|
+
|
468
|
+
static void single_test_free(patch_t* world, size_t* nb_indices, double* patch_rates, double* sum_rates_by_row) {
|
469
|
+
free(world);
|
470
|
+
free(nb_indices);
|
471
|
+
free(patch_rates);
|
472
|
+
free(sum_rates_by_row);
|
473
|
+
}
|
474
|
+
|
475
|
+
|
476
|
+
|
477
|
+
void run(model_t* mod, char* message, size_t msg_len) {
|
478
|
+
if (!mod->data_empty) {
|
479
|
+
fprintf(stdout, "Error: mod has non-empty data\n");
|
480
|
+
fflush(stdout);
|
481
|
+
return; // Or handle error as you see fit
|
482
|
+
}
|
483
|
+
|
484
|
+
double start = clock();
|
485
|
+
|
486
|
+
mod->data_empty = false;
|
487
|
+
|
488
|
+
// initialize random
|
489
|
+
if (mod->seed != -1) {
|
490
|
+
srand((uint32_t) mod->seed);
|
491
|
+
} else {
|
492
|
+
srand(time(NULL));
|
493
|
+
}
|
494
|
+
|
495
|
+
if (mod->seed == -1){
|
496
|
+
srand(time(NULL));
|
497
|
+
} else {
|
498
|
+
srand(mod->seed);
|
499
|
+
}
|
500
|
+
|
501
|
+
if (mod->print_pct == 0) {
|
502
|
+
mod->print_pct = 5; // default print_pct
|
503
|
+
}
|
504
|
+
|
505
|
+
uint32_t update_sum_frequency = 16;
|
506
|
+
size_t i = 0;
|
507
|
+
|
508
|
+
while (i < mod->sim_time) {
|
509
|
+
char curr_msg[20 + msg_len]; // message for current round
|
510
|
+
strcpy(curr_msg, message);
|
511
|
+
strcat(curr_msg, "round ");
|
512
|
+
snprintf(curr_msg + strlen(curr_msg), sizeof(curr_msg) - strlen(curr_msg), "%zu", i);
|
513
|
+
|
514
|
+
/*if (predict_runtime && i > 0) {
|
515
|
+
double time_elapsed = timer() - start;
|
516
|
+
double pred_runtime = time_elapsed / i * (mod->sim_time - i);
|
517
|
+
snprintf(end_info, sizeof(end_info), ", ~%.2fs left", pred_runtime);
|
518
|
+
}*/
|
519
|
+
|
520
|
+
uint32_t result = GENERAL_FAILURE;
|
521
|
+
single_test(mod, update_sum_frequency, &result, curr_msg);
|
522
|
+
|
523
|
+
switch (result) {
|
524
|
+
case SUCCESS:
|
525
|
+
i++;
|
526
|
+
break;
|
527
|
+
case SMALL_MAXTIME:
|
528
|
+
fprintf(stdout, "Error: maxtime too small.\n");
|
529
|
+
fflush(stdout);
|
530
|
+
return;
|
531
|
+
case GENERAL_FAILURE:
|
532
|
+
// Possibly Numerical issue, increase precision
|
533
|
+
update_sum_frequency *= 4;
|
534
|
+
if (update_sum_frequency > 1e5) {
|
535
|
+
fprintf(stdout, "Error: input model not handable.\n");
|
536
|
+
fflush(stdout);
|
537
|
+
return;
|
538
|
+
}
|
539
|
+
fprintf(stdout, "Possible numerical issue at round %zu. Trying higher precision now.\n", i);
|
540
|
+
fflush(stdout);
|
541
|
+
break;
|
542
|
+
case OVERFLOW:
|
543
|
+
// error message is handled by single_test
|
544
|
+
return;
|
545
|
+
default:
|
546
|
+
fprintf(stdout, "Error: unkown behavior.\n");
|
547
|
+
fflush(stdout);
|
548
|
+
return;
|
549
|
+
}
|
550
|
+
}
|
551
|
+
|
552
|
+
calculate_ave(mod);
|
553
|
+
|
554
|
+
double stop = clock();
|
555
|
+
|
556
|
+
fprintf(stdout, "\r%sruntime: %.3fs \n", message, (double)(stop - start) / CLOCKS_PER_SEC);
|
557
|
+
fflush(stdout);
|
558
|
+
}
|
559
|
+
|
560
|
+
|
561
|
+
|