piegy 2.3.6__tar.gz → 2.3.8__tar.gz

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.
Files changed (35) hide show
  1. {piegy-2.3.6 → piegy-2.3.8}/MANIFEST.in +1 -0
  2. {piegy-2.3.6/src/piegy.egg-info → piegy-2.3.8}/PKG-INFO +1 -1
  3. {piegy-2.3.6 → piegy-2.3.8}/pyproject.toml +1 -1
  4. piegy-2.3.8/src/piegy/C_core/patch.c +53 -0
  5. {piegy-2.3.6 → piegy-2.3.8}/src/piegy/C_core/patch.h +9 -6
  6. {piegy-2.3.6 → piegy-2.3.8}/src/piegy/C_core/sim_funcs.c +111 -106
  7. {piegy-2.3.6 → piegy-2.3.8}/src/piegy/C_core/sim_funcs.h +37 -43
  8. {piegy-2.3.6 → piegy-2.3.8}/src/piegy/__init__.py +2 -2
  9. {piegy-2.3.6 → piegy-2.3.8}/src/piegy/__version__.py +3 -1
  10. {piegy-2.3.6 → piegy-2.3.8}/src/piegy/data_tools.py +33 -45
  11. {piegy-2.3.6 → piegy-2.3.8}/src/piegy/figures.py +3 -3
  12. {piegy-2.3.6 → piegy-2.3.8}/src/piegy/simulation.py +7 -7
  13. {piegy-2.3.6 → piegy-2.3.8}/src/piegy/test_var.py +21 -15
  14. {piegy-2.3.6 → piegy-2.3.8}/src/piegy/tools/figure_tools.py +1 -1
  15. {piegy-2.3.6 → piegy-2.3.8}/src/piegy/tools/find_C.py +3 -4
  16. {piegy-2.3.6 → piegy-2.3.8}/src/piegy/videos.py +14 -11
  17. {piegy-2.3.6 → piegy-2.3.8/src/piegy.egg-info}/PKG-INFO +1 -1
  18. {piegy-2.3.6 → piegy-2.3.8}/src/piegy.egg-info/SOURCES.txt +0 -1
  19. piegy-2.3.6/src/piegy/C_core/patch.c +0 -43
  20. piegy-2.3.6/src/piegy/C_core/runner.c +0 -61
  21. {piegy-2.3.6 → piegy-2.3.8}/LICENSE.txt +0 -0
  22. {piegy-2.3.6 → piegy-2.3.8}/README.md +0 -0
  23. {piegy-2.3.6 → piegy-2.3.8}/setup.cfg +0 -0
  24. {piegy-2.3.6 → piegy-2.3.8}/setup.py +0 -0
  25. {piegy-2.3.6 → piegy-2.3.8}/src/piegy/C_core/Makefile +0 -0
  26. {piegy-2.3.6 → piegy-2.3.8}/src/piegy/C_core/model.c +0 -0
  27. {piegy-2.3.6 → piegy-2.3.8}/src/piegy/C_core/model.h +0 -0
  28. {piegy-2.3.6 → piegy-2.3.8}/src/piegy/analysis.py +0 -0
  29. {piegy-2.3.6 → piegy-2.3.8}/src/piegy/build_info.py +0 -0
  30. {piegy-2.3.6 → piegy-2.3.8}/src/piegy/simulation_py.py +0 -0
  31. {piegy-2.3.6 → piegy-2.3.8}/src/piegy/tools/__init__.py +0 -0
  32. {piegy-2.3.6 → piegy-2.3.8}/src/piegy/tools/file_tools.py +0 -0
  33. {piegy-2.3.6 → piegy-2.3.8}/src/piegy.egg-info/dependency_links.txt +0 -0
  34. {piegy-2.3.6 → piegy-2.3.8}/src/piegy.egg-info/requires.txt +0 -0
  35. {piegy-2.3.6 → piegy-2.3.8}/src/piegy.egg-info/top_level.txt +0 -0
@@ -4,3 +4,4 @@ include LICENSE.txt
4
4
  include src/piegy/C_core/*.c
5
5
  include src/piegy/C_core/*.h
6
6
  include src/piegy/C_core/Makefile
7
+ exclude src/piegy/C_core/runner.c
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: piegy
3
- Version: 2.3.6
3
+ Version: 2.3.8
4
4
  Summary: Payoff-Driven Stochastic Spatial Model for Evolutionary Game Theory
5
5
  Author-email: Chenning Xu <cxu7@caltech.edu>
6
6
  License: BSD 3-Clause License
@@ -4,7 +4,7 @@ build-backend = 'setuptools.build_meta'
4
4
 
5
5
  [project]
6
6
  name = 'piegy'
7
- version = '2.3.6'
7
+ version = '2.3.8'
8
8
  description = 'Payoff-Driven Stochastic Spatial Model for Evolutionary Game Theory'
9
9
  readme = 'README.md'
10
10
  requires-python = '>=3.7'
@@ -0,0 +1,53 @@
1
+ /**
2
+ * This .c includes the patch struct and "member functions"
3
+ * that correponds to patch class in piegy.model module
4
+ */
5
+
6
+ #include "patch.h"
7
+
8
+ void patch_init(patch_t* p, uint32_t U, uint32_t V, size_t row, size_t col, double* X_start, double* P_start) {
9
+ if (p == NULL) return;
10
+ p->row = row;
11
+ p->col = col;
12
+
13
+ p->U = U;
14
+ p->V = V;
15
+ p->U_pi = 0;
16
+ p->V_pi = 0;
17
+
18
+ memcpy(p->X, X_start, 4 * sizeof(double));
19
+ memcpy(p->P, P_start, 6 * sizeof(double));
20
+ for (size_t i = 0; i < 6; i++) {
21
+ p->P[i] = P_start[i];
22
+ }
23
+
24
+ for (size_t i = 0; i < 4; i++) {
25
+ p->U_weight[i] = 0;
26
+ p->V_weight[i] = 0;
27
+ p->pi_death_rates[i] = 0;
28
+ }
29
+ for (size_t i = 0; i < 8; i++) {
30
+ p->mig_rates[i] = 0;
31
+ }
32
+ p->sum_U_weight = 0;
33
+ p->sum_V_weight = 0;
34
+ p->sum_pi_death_rates = 0;
35
+ p->sum_mig_rates = 0;
36
+ }
37
+
38
+
39
+ void set_nb(patch_t* world, size_t* nb_start, size_t ij, size_t NM) {
40
+ // nb_start is the where patch ij's neighbor indices start
41
+ size_t num_nb = 0;
42
+ for (size_t k = 0; k < 4; k++) {
43
+ if (nb_start[k] != NM) {
44
+ // neighbor is valid
45
+ world[ij].nb[k] = &world[nb_start[k]];
46
+ num_nb += 1;
47
+ } else {
48
+ world[ij].nb[k] = NULL;
49
+ }
50
+ }
51
+ world[ij].P[0] *= (0.25 * num_nb);
52
+ world[ij].P[1] *= (0.25 * num_nb);
53
+ }
@@ -10,18 +10,21 @@
10
10
  #include <stdio.h>
11
11
  #include <stdint.h>
12
12
  #include <stdbool.h>
13
-
13
+ #include <string.h>
14
14
 
15
15
 
16
16
  typedef struct patch_t {
17
- size_t i;
18
- size_t j;
17
+ size_t row;
18
+ size_t col;
19
19
 
20
- uint32_t U;
20
+ uint32_t U; // store as double directly to avoid runtime conversion (to double)
21
21
  uint32_t V;
22
22
  double U_pi;
23
23
  double V_pi;
24
24
 
25
+ double X[4]; // a copy of matrix and patch variables (mu, w, kappa)
26
+ double P[6];
27
+
25
28
  struct patch_t* nb[4];
26
29
  double U_weight[4]; // stores migration weight of each of the 4 neighbors
27
30
  double V_weight[4];
@@ -34,8 +37,8 @@ typedef struct patch_t {
34
37
  } patch_t;
35
38
 
36
39
  // in .c
37
- void patch_init(patch_t* p, uint32_t U, uint32_t V, size_t i, size_t j);
38
- void set_nb(patch_t* world, size_t* nb_start, size_t ij, size_t NM);
40
+ void patch_init(patch_t* p, uint32_t U, uint32_t V, size_t row, size_t col, double* X_start, double* P_start);
41
+ void set_nb(patch_t* world, size_t* nb_start, size_t ij, size_t NM) ;
39
42
 
40
43
  #endif // PATCH_H
41
44
 
@@ -76,68 +76,60 @@ static double single_init(const model_t* restrict mod, patch_t* restrict world,
76
76
  size_t M = mod->M;
77
77
  size_t NM = N * M;
78
78
  size_t max_record = mod->max_record;
79
- size_t ij = 0; // used to track index i * M + j in double for loops
79
+ size_t ij_out = 0; // used to track index i * M + j in double for loops, "out" means not the "looper" in for loop
80
80
 
81
81
  // init world
82
82
  for (size_t i = 0; i < N; i++) {
83
83
  for (size_t j = 0; j < M; j++) {
84
- patch_init(&world[ij], mod->I[ij * 2], mod->I[ij * 2 + 1], i, j);
85
- ij++;
84
+ patch_init(&world[ij_out], mod->I[ij_out * 2], mod->I[ij_out * 2 + 1], i, j, &(mod->X[ij_out * 4]), &(mod->P[ij_out * 6]));
85
+ ij_out++;
86
86
  }
87
87
  }
88
88
 
89
89
  // init nb_indices
90
- ij = 0;
90
+ ij_out = 0;
91
91
  if (mod->boundary) {
92
92
  for (size_t i = 0; i < N; i++) {
93
93
  for (size_t j = 0; j < M; j++) {
94
- find_nb_zero_flux(&nb_indices[ij * 4], i, j, N, M, NM);
95
- ij++;
94
+ find_nb_zero_flux(&nb_indices[ij_out * 4], i, j, N, M, NM);
95
+ ij_out++;
96
96
  }
97
97
  }
98
98
  } else {
99
99
  for (size_t i = 0; i < N; i++) {
100
100
  for (size_t j = 0; j < M; j++) {
101
- find_nb_periodical(&nb_indices[ij * 4], i, j, N, M, NM);
102
- ij++;
101
+ find_nb_periodical(&nb_indices[ij_out * 4], i, j, N, M, NM);
102
+ ij_out++;
103
103
  }
104
104
  }
105
105
  }
106
106
 
107
107
 
108
108
  // set nb pointers for patches
109
- ij = 0;
110
- for (size_t i = 0; i < N; i++) {
111
- for (size_t j = 0; j < M; j++) {
112
- set_nb(world, &nb_indices[ij * 4], ij, NM);
113
- ij++;
114
- }
109
+ for (size_t ij = 0; ij < NM; ij++) {
110
+ set_nb(world, &nb_indices[ij * 4], ij, NM);
115
111
  }
116
112
 
117
113
  //////// Begin Running ////////
118
114
 
119
115
  // init payoff & natural death rates
120
- ij = 0;
121
- for (size_t i = 0; i < N; i++) {
122
- for (size_t j = 0; j < M; j++) {
123
- update_pi_k(&world[ij], &(mod->X[ij * 4]), &(mod->P[ij * 6]));
124
- ij++;
125
- }
116
+ for (size_t ij = 0; ij < N; ij++) {
117
+ update_pi_k(&world[ij]);
126
118
  }
127
119
 
128
120
  // init migration rates & store patch rates
129
- ij = 0;
121
+ ij_out = 0;
130
122
  for (size_t i = 0; i < N; i++) {
131
123
  for (size_t j = 0; j < M; j++) {
132
- uint8_t mig_result = init_mig(&world[ij], &(mod->P[ij * 6])); // init mig rates for all 4 directions
124
+ uint8_t mig_result = init_mig(&world[ij_out]); // init mig rates for all 4 directions
133
125
  if (mig_result == SIM_OVERFLOW) {
134
126
  return -1 * SIM_OVERFLOW;
135
127
  }
136
- double ij_rates = world[ij].sum_pi_death_rates + world[ij].sum_mig_rates;
137
- patch_rates[ij] = ij_rates;
128
+ double ij_rates = world[ij_out].sum_pi_death_rates + world[ij_out].sum_mig_rates;
129
+ patch_rates[ij_out] = ij_rates;
138
130
  sum_rates_by_row[i] += ij_rates;
139
131
  *sum_rates_p = *sum_rates_p + ij_rates; // can't do *sum_rates_p += ij_rates
140
- ij++;
132
+ ij_out++;
141
133
  }
142
134
  }
143
135
 
@@ -172,22 +164,20 @@ static double single_init(const model_t* restrict mod, patch_t* restrict world,
172
164
  // maxtime too small
173
165
  return -1 * SMALL_MAXTIME;
174
166
  }
175
-
167
+
176
168
  // store data
177
169
  if (time > mod->record_itv) {
178
170
  size_t recod_idx = (size_t) (time / mod->record_itv);
179
- ij = 0;
180
- for (size_t i = 0; i < N; i++) {
181
- for (size_t j = 0; j < M; j++) {
182
- for (size_t k = 0; k < recod_idx; k++) {
183
- mod->U1d[ij * max_record + k] += world[ij].U;
184
- mod->V1d[ij * max_record + k] += world[ij].V;
185
- mod->Upi_1d[ij * max_record + k] += world[ij].U_pi;
186
- mod->Vpi_1d[ij * max_record + k] += world[ij].V_pi;
187
- }
188
- ij++;
171
+
172
+ for (size_t ij = 0; ij < NM; ij++) {
173
+ size_t ij_max_record = ij * max_record;
174
+ for (size_t k = 0; k < recod_idx; k++) {
175
+ mod->U1d[ij_max_record + k] += world[ij].U;
176
+ mod->V1d[ij_max_record + k] += world[ij].V;
177
+ mod->Upi_1d[ij_max_record + k] += world[ij].U_pi;
178
+ mod->Vpi_1d[ij_max_record + k] += world[ij].V_pi;
189
179
  }
190
- }
180
+ }
191
181
  }
192
182
 
193
183
  return time;
@@ -204,29 +194,20 @@ static uint8_t single_test(model_t* restrict mod, char* message) {
204
194
  size_t max_record = mod->max_record;
205
195
  double record_itv = mod->record_itv;
206
196
  bool boundary = mod->boundary;
207
-
208
- // print progress
209
- double one_progress = 0.0;
210
- double current_progress = one_progress;
211
- if (mod->print_pct != -1) {
212
- one_progress = maxtime * mod->print_pct / 100.0;
213
- fprintf(stdout, "\r ");
214
- fprintf(stdout, "\r%s: 0 %%", message);
215
- fflush(stdout);
216
- } else {
217
- one_progress = 2.0 * maxtime;
218
- }
197
+ double* mod_U1d = mod->U1d;
198
+ double* mod_V1d = mod->V1d;
199
+ double* mod_Upi_1d = mod->Upi_1d;
200
+ double* mod_Vpi_1d = mod->Vpi_1d;
219
201
 
220
202
  // update sum of rates every 1e5 rounds
221
203
  // many rates are updated each time, rather than re-calculated.
222
204
  // So need to re-calculate from scratch every some rounds to reduce numerical errors
223
205
  size_t curr_update_sum_round = 0; // current round
224
- size_t update_sum_rounds = UPDATE_SUM_ROUNDS_SM; // recalculate sum every this many rounds
206
+ size_t update_sum_freq = UPDATE_SUM_ROUNDS_SM; // recalculate sum every this many rounds
225
207
 
226
- // Initialize simulation
208
+ // core containers
227
209
  patch_t* world = (patch_t*) calloc(NM, sizeof(patch_t));
228
210
  size_t* nb_indices = (size_t*) calloc(NM * 4, sizeof(size_t));
229
-
230
211
  double* patch_rates = (double*) calloc(NM, sizeof(double));
231
212
  double* sum_rates_by_row = (double*) calloc(N, sizeof(double));
232
213
  double sum_rates = 0;
@@ -234,6 +215,17 @@ static uint8_t single_test(model_t* restrict mod, char* message) {
234
215
  signal_t signal;
235
216
  patch_picked_t picked;
236
217
 
218
+ // print progress
219
+ double one_progress = one_progress = 2.0 * maxtime;
220
+ if (mod->print_pct != -1) {
221
+ one_progress = maxtime * mod->print_pct / 100.0;
222
+ fprintf(stdout, "\r ");
223
+ fprintf(stdout, "\r%s: 0 %%", message);
224
+ fflush(stdout);
225
+ }
226
+ double current_progress = one_progress;
227
+
228
+ // Call single_init. Initialize rates and run for 1 event
237
229
  double time = single_init(mod, world, nb_indices, patch_rates, sum_rates_by_row, &sum_rates, &signal, &picked);
238
230
  if (time == -1 * SMALL_MAXTIME) {
239
231
  // time too small
@@ -251,32 +243,36 @@ static uint8_t single_test(model_t* restrict mod, char* message) {
251
243
  fflush(stdout);
252
244
  single_test_free(&world, &nb_indices, &patch_rates, &sum_rates_by_row);
253
245
  return ACCURACY_ERROR;
254
- }
255
- size_t record_index = time / mod->record_itv;
246
+ }
247
+ size_t record_index = (size_t) (time / mod->record_itv);
256
248
  double record_time = time - record_index * record_itv;
257
249
 
250
+ //////// while loop ////////
258
251
 
259
252
  while (time < maxtime) {
260
253
 
261
- // Print progress
262
- if (time > current_progress) {
263
- uint8_t curr_prog = (uint8_t)(time * 100 / maxtime);
264
- if (curr_prog < 10) {
265
- fprintf(stdout, "\r%s: %d %%", message, (int)(time * 100 / maxtime));
266
- } else {
267
- fprintf(stdout, "\r%s: %d%%", message, (int)(time * 100 / maxtime));
268
- }
269
- fflush(stdout);
270
- //fflush(stdout); // Make sure it prints immediately
271
- current_progress += one_progress;
272
- }
273
-
274
- // update sums
254
+ // update sums and print progress
275
255
  curr_update_sum_round++;
276
- if (curr_update_sum_round > update_sum_rounds) {
256
+ if (curr_update_sum_round > update_sum_freq) {
277
257
  curr_update_sum_round = 0;
278
258
 
279
- update_sum_rounds = UPDATE_SUM_ROUNDS_LG; // assume can make it larger
259
+ // Print progress
260
+ if (time > current_progress) {
261
+ uint8_t curr_prog = (uint8_t)(time * 100 / maxtime);
262
+ if (curr_prog < 10) {
263
+ fprintf(stdout, "\r%s: %d %%", message, (int)(time * 100 / maxtime));
264
+ } else {
265
+ fprintf(stdout, "\r%s: %d%%", message, (int)(time * 100 / maxtime));
266
+ }
267
+ fflush(stdout);
268
+ //fprintf(stdout, "\n99: %d, %d, %f, %f\n100: %d, %d, %f, %f\n",
269
+ //world[98].U, world[98].V, world[98].mig_rates[3], world[98].mig_rates[7], world[99].U, world[99].V, world[99].mig_rates[2], world[99].mig_rates[6]);
270
+ //fflush(stdout);
271
+ current_progress += one_progress;
272
+ }
273
+
274
+ // update sum
275
+ update_sum_freq = UPDATE_SUM_ROUNDS_LG; // assume can make it larger
280
276
  for (size_t ij = 0; ij < NM; ij++) {
281
277
  double sum_U_weight = 0;
282
278
  double sum_V_weight = 0;
@@ -285,19 +281,19 @@ static uint8_t single_test(model_t* restrict mod, char* message) {
285
281
  sum_V_weight += world[ij].V_weight[k];
286
282
  }
287
283
  if (sum_U_weight > ACCURATE_BOUND || sum_V_weight > ACCURATE_BOUND) {
288
- update_sum_rounds = UPDATE_SUM_ROUNDS_SM; // values too large, put back the small update frequency
284
+ update_sum_freq = UPDATE_SUM_ROUNDS_SM; // values too large, put back the small update frequency
289
285
  }
290
286
  world[ij].sum_U_weight = sum_U_weight;
291
287
  world[ij].sum_V_weight = sum_V_weight;
292
288
  // patch_rates are updated every time a patch is changed
293
289
  }
294
- size_t ij = 0;
290
+ size_t ij_out = 0;
295
291
  sum_rates = 0;
296
292
  for (size_t i = 0; i < N; i++) {
297
293
  double sum_rates_by_row_i = 0;
298
294
  for (size_t j = 0; j < M; j++) {
299
- sum_rates_by_row_i += patch_rates[ij];
300
- ij++;
295
+ sum_rates_by_row_i += patch_rates[ij_out];
296
+ ij_out++;
301
297
  }
302
298
  sum_rates_by_row[i] = sum_rates_by_row_i;
303
299
  sum_rates += sum_rates_by_row_i;
@@ -318,8 +314,8 @@ static uint8_t single_test(model_t* restrict mod, char* message) {
318
314
  sum_rates_by_row[si1] -= patch_rates[sij1];
319
315
  sum_rates -= patch_rates[sij1];
320
316
 
321
- update_pi_k(&world[sij1], &(mod->X[sij1 * 4]), &(mod->P[sij1 * 6]));
322
- update_mig_just_rate(&world[sij1], &(mod->P[sij1 * 6]));
317
+ update_pi_k(&world[sij1]);
318
+ update_mig_just_rate(&world[sij1]);
323
319
 
324
320
  patch_rates[sij1] = world[sij1].sum_pi_death_rates + world[sij1].sum_mig_rates;
325
321
  sum_rates_by_row[si1] += patch_rates[sij1];
@@ -331,11 +327,11 @@ static uint8_t single_test(model_t* restrict mod, char* message) {
331
327
  sum_rates -= patch_rates[sij1];
332
328
  sum_rates -= patch_rates[sij2];
333
329
 
334
- update_pi_k(&world[sij1], &(mod->X[sij1 * 4]), &(mod->P[sij1 * 6])); // update both patches' payoffs first
335
- update_pi_k(&world[sij2], &(mod->X[sij2 * 4]), &(mod->P[sij2 * 6]));
330
+ update_pi_k(&world[sij1]); // update both patches' payoffs first
331
+ update_pi_k(&world[sij2]);
336
332
 
337
- if (update_mig_weight_rate(&world[sij1], &(mod->P[sij1 * 6]), rela_loc) == SIM_OVERFLOW ||
338
- update_mig_weight_rate(&world[sij2], &(mod->P[sij2 * 6]), rela_loc ^ 1) == SIM_OVERFLOW) {
333
+ if (update_mig_weight_rate(&world[sij1], rela_loc) == SIM_OVERFLOW ||
334
+ update_mig_weight_rate(&world[sij2], rela_loc ^ 1) == SIM_OVERFLOW) {
339
335
 
340
336
  fprintf(stdout, "\nError: overflow at t = %f\n", time);
341
337
  fflush(stdout);
@@ -357,7 +353,7 @@ static uint8_t single_test(model_t* restrict mod, char* message) {
357
353
  size_t nb_idx = nb_indices[sij1 * 4 + k];
358
354
  if (nb_idx == NM) { continue; } // invalid neighbor
359
355
  // all neighbors, as long as exists, need to change
360
- if (update_mig_weight_rate(&world[nb_idx], &(mod->P[nb_idx * 6]), k ^ 1) == SIM_OVERFLOW) {
356
+ if (update_mig_weight_rate(&world[nb_idx], k ^ 1) == SIM_OVERFLOW) {
361
357
  fprintf(stdout, "\nError: overflow at t = %f\n", time);
362
358
  fflush(stdout);
363
359
  single_test_free(&world, &nb_indices, &patch_rates, &sum_rates_by_row);
@@ -372,7 +368,7 @@ static uint8_t single_test(model_t* restrict mod, char* message) {
372
368
  if (nb_idx == NM) { continue; }
373
369
  if (k != rela_loc) {
374
370
  // nb_idx isn't the second last-changed patch
375
- if (update_mig_weight_rate(&world[nb_idx], &(mod->P[nb_idx * 6]), k ^ 1) == SIM_OVERFLOW) {
371
+ if (update_mig_weight_rate(&world[nb_idx], k ^ 1) == SIM_OVERFLOW) {
376
372
  fprintf(stdout, "\nError: overflow at t = %f\n", time);
377
373
  fflush(stdout);
378
374
  single_test_free(&world, &nb_indices, &patch_rates, &sum_rates_by_row);
@@ -386,7 +382,7 @@ static uint8_t single_test(model_t* restrict mod, char* message) {
386
382
  if (nb_idx == NM) { continue; }
387
383
  if (k != (rela_loc ^ 1)) {
388
384
  // nb_idx isn't the first last-changed patch
389
- if (update_mig_weight_rate(&world[nb_idx], &(mod->P[nb_idx * 6]), k ^ 1) == SIM_OVERFLOW) {
385
+ if (update_mig_weight_rate(&world[nb_idx], k ^ 1) == SIM_OVERFLOW) {
390
386
  fprintf(stdout, "\nError: overflow at t = %f\n", time);
391
387
  fflush(stdout);
392
388
  single_test_free(&world, &nb_indices, &patch_rates, &sum_rates_by_row);
@@ -396,7 +392,6 @@ static uint8_t single_test(model_t* restrict mod, char* message) {
396
392
  }
397
393
  }
398
394
 
399
-
400
395
  // pick a random event
401
396
  double expected_sum = random01() * sum_rates;
402
397
  find_patch(&picked, expected_sum, patch_rates, sum_rates_by_row, sum_rates, N, M);
@@ -416,7 +411,7 @@ static uint8_t single_test(model_t* restrict mod, char* message) {
416
411
  make_signal_periodical(N, M, picked.i, picked.j, e0, &signal);
417
412
  }
418
413
  signal.ij1 = signal.i1 * M + signal.j1;
419
- signal.ij2 = signal.i2 * M + signal.j2;
414
+ signal.ij2 = signal.i2 * M + signal.j2;
420
415
 
421
416
  // let the event happenn
422
417
  change_popu(&world[signal.ij1], signal.e1);
@@ -437,11 +432,12 @@ static uint8_t single_test(model_t* restrict mod, char* message) {
437
432
  size_t upper = record_index + multi_records;
438
433
 
439
434
  for (size_t ij = 0; ij < NM; ij++) {
435
+ size_t ij_max_record = ij * max_record;
440
436
  for (size_t k = record_index; k < upper; k++) {
441
- mod->U1d[ij * max_record + k] += world[ij].U;
442
- mod->V1d[ij * max_record + k] += world[ij].V;
443
- mod->Upi_1d[ij * max_record + k] += world[ij].U_pi;
444
- mod->Vpi_1d[ij * max_record + k] += world[ij].V_pi;
437
+ mod_U1d[ij_max_record + k] += world[ij].U;
438
+ mod_V1d[ij_max_record + k] += world[ij].V;
439
+ mod_Upi_1d[ij_max_record + k] += world[ij].U_pi;
440
+ mod_Vpi_1d[ij_max_record + k] += world[ij].V_pi;
445
441
  }
446
442
  }
447
443
  record_index += multi_records;
@@ -450,11 +446,12 @@ static uint8_t single_test(model_t* restrict mod, char* message) {
450
446
  } else {
451
447
  // if already exceeds maxtime
452
448
  for (size_t ij = 0; ij < NM; ij++) {
449
+ size_t ij_max_record = ij * max_record;
453
450
  for (size_t k = record_index; k < max_record; k++) {
454
- mod->U1d[ij * max_record + k] += world[ij].U;
455
- mod->V1d[ij * max_record + k] += world[ij].V;
456
- mod->Upi_1d[ij * max_record + k] += world[ij].U_pi;
457
- mod->Vpi_1d[ij * max_record + k] += world[ij].V_pi;
451
+ mod_U1d[ij_max_record + k] += world[ij].U;
452
+ mod_V1d[ij_max_record + k] += world[ij].V;
453
+ mod_Upi_1d[ij_max_record + k] += world[ij].U_pi;
454
+ mod_Vpi_1d[ij_max_record + k] += world[ij].V_pi;
458
455
  }
459
456
  }
460
457
  }
@@ -514,27 +511,33 @@ uint8_t run(model_t* restrict mod, char* message, size_t msg_len) {
514
511
 
515
512
  if (mod->print_pct == 0) {
516
513
  mod->print_pct = 5; // default print_pct
514
+ }
515
+ size_t print_round = 0; // print every some round if print_pct == x * 100, set to 0 for not printing
516
+ if (mod->print_pct >= 100) {
517
+ print_round = mod->print_pct / 100; // print progress every some round
518
+ mod->print_pct = -1; // not printing progress in single_test
517
519
  }
518
520
 
519
- size_t i = 0;
521
+ size_t round = 0;
520
522
 
521
- while (i < mod->sim_time) {
523
+ while (round < mod->sim_time) {
522
524
  char curr_msg[100 + msg_len]; // message for current round
523
525
  strcpy(curr_msg, message);
524
526
  strcat(curr_msg, "round ");
525
- snprintf(curr_msg + strlen(curr_msg), sizeof(curr_msg) - strlen(curr_msg), "%zu", i);
527
+ snprintf(curr_msg + strlen(curr_msg), sizeof(curr_msg) - strlen(curr_msg), "%zu", round);
526
528
 
527
- /*if (predict_runtime && i > 0) {
528
- double time_elapsed = timer() - start;
529
- double pred_runtime = time_elapsed / i * (mod->sim_time - i);
530
- snprintf(end_info, sizeof(end_info), ", ~%.2fs left", pred_runtime);
531
- }*/
529
+ if ((print_round != 0) && (round % print_round == 0)) {
530
+ // only printing the round number
531
+ // add "!= 0" because round 0 could trigger printing
532
+ fprintf(stdout, "\r%s", curr_msg);
533
+ fflush(stdout);
534
+ }
532
535
 
533
536
  uint8_t result = single_test(mod, curr_msg);
534
537
 
535
538
  switch (result) {
536
539
  case SUCCESS:
537
- i++;
540
+ round++;
538
541
  break;
539
542
  case SMALL_MAXTIME:
540
543
  // error message is handled by single_test
@@ -550,10 +553,12 @@ uint8_t run(model_t* restrict mod, char* message, size_t msg_len) {
550
553
 
551
554
  calculate_ave(mod);
552
555
 
553
- double stop = clock();
554
-
555
- fprintf(stdout, "\r%sruntime: %.3fs \n", message, (double)(stop - start) / CLOCKS_PER_SEC);
556
- fflush(stdout);
556
+ if ((mod->print_pct != -1) || (print_round != 0)) {
557
+ // print runtime if the original mod->print_pct != -1
558
+ double stop = clock();
559
+ fprintf(stdout, "\r%sruntime: %.3fs \n", message, (double)(stop - start) / CLOCKS_PER_SEC);
560
+ fflush(stdout);
561
+ }
557
562
  return SUCCESS;
558
563
  }
559
564