piegy 2.3.7__tar.gz → 2.3.9__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.
- {piegy-2.3.7/src/piegy.egg-info → piegy-2.3.9}/PKG-INFO +1 -1
- {piegy-2.3.7 → piegy-2.3.9}/pyproject.toml +1 -1
- {piegy-2.3.7 → piegy-2.3.9}/src/piegy/C_core/model.c +8 -9
- {piegy-2.3.7 → piegy-2.3.9}/src/piegy/C_core/patch.c +17 -14
- {piegy-2.3.7 → piegy-2.3.9}/src/piegy/C_core/patch.h +6 -3
- piegy-2.3.9/src/piegy/C_core/random.h +77 -0
- {piegy-2.3.7 → piegy-2.3.9}/src/piegy/C_core/sim_funcs.c +76 -73
- {piegy-2.3.7 → piegy-2.3.9}/src/piegy/C_core/sim_funcs.h +34 -54
- {piegy-2.3.7 → piegy-2.3.9}/src/piegy/__init__.py +2 -2
- {piegy-2.3.7 → piegy-2.3.9}/src/piegy/__version__.py +3 -1
- {piegy-2.3.7 → piegy-2.3.9}/src/piegy/data_tools.py +22 -13
- {piegy-2.3.7 → piegy-2.3.9}/src/piegy/simulation.py +7 -16
- {piegy-2.3.7 → piegy-2.3.9}/src/piegy/simulation_py.py +17 -9
- {piegy-2.3.7 → piegy-2.3.9}/src/piegy/test_var.py +8 -8
- {piegy-2.3.7 → piegy-2.3.9/src/piegy.egg-info}/PKG-INFO +1 -1
- {piegy-2.3.7 → piegy-2.3.9}/src/piegy.egg-info/SOURCES.txt +1 -0
- {piegy-2.3.7 → piegy-2.3.9}/LICENSE.txt +0 -0
- {piegy-2.3.7 → piegy-2.3.9}/MANIFEST.in +0 -0
- {piegy-2.3.7 → piegy-2.3.9}/README.md +0 -0
- {piegy-2.3.7 → piegy-2.3.9}/setup.cfg +0 -0
- {piegy-2.3.7 → piegy-2.3.9}/setup.py +0 -0
- {piegy-2.3.7 → piegy-2.3.9}/src/piegy/C_core/Makefile +0 -0
- {piegy-2.3.7 → piegy-2.3.9}/src/piegy/C_core/model.h +0 -0
- {piegy-2.3.7 → piegy-2.3.9}/src/piegy/analysis.py +0 -0
- {piegy-2.3.7 → piegy-2.3.9}/src/piegy/build_info.py +0 -0
- {piegy-2.3.7 → piegy-2.3.9}/src/piegy/figures.py +0 -0
- {piegy-2.3.7 → piegy-2.3.9}/src/piegy/tools/__init__.py +0 -0
- {piegy-2.3.7 → piegy-2.3.9}/src/piegy/tools/figure_tools.py +0 -0
- {piegy-2.3.7 → piegy-2.3.9}/src/piegy/tools/file_tools.py +0 -0
- {piegy-2.3.7 → piegy-2.3.9}/src/piegy/tools/find_C.py +0 -0
- {piegy-2.3.7 → piegy-2.3.9}/src/piegy/videos.py +0 -0
- {piegy-2.3.7 → piegy-2.3.9}/src/piegy.egg-info/dependency_links.txt +0 -0
- {piegy-2.3.7 → piegy-2.3.9}/src/piegy.egg-info/requires.txt +0 -0
- {piegy-2.3.7 → piegy-2.3.9}/src/piegy.egg-info/top_level.txt +0 -0
@@ -79,17 +79,16 @@ void mod_free(model_t* mod) {
|
|
79
79
|
|
80
80
|
void mod_free_py(model_t* mod) {
|
81
81
|
// free function for python
|
82
|
-
|
82
|
+
// the same as mod_free except for not having free(mod)
|
83
83
|
if (!mod) return;
|
84
|
-
if (mod->I) { free(mod->I); }
|
85
|
-
if (mod->X) { free(mod->X); }
|
86
|
-
if (mod->P) { free(mod->P); }
|
87
|
-
if (mod->U1d) { free(mod->U1d); }
|
88
|
-
if (mod->V1d) { free(mod->V1d); }
|
89
|
-
if (mod->Upi_1d) { free(mod->Upi_1d); }
|
90
|
-
if (mod->Vpi_1d) { free(mod->Vpi_1d); }
|
91
|
-
// if (mod) { free(mod); }
|
92
84
|
|
85
|
+
free(mod->I);
|
86
|
+
free(mod->X);
|
87
|
+
free(mod->P);
|
88
|
+
free(mod->U1d);
|
89
|
+
free(mod->V1d);
|
90
|
+
free(mod->Upi_1d);
|
91
|
+
free(mod->Vpi_1d);
|
93
92
|
mod->I = NULL;
|
94
93
|
mod->X = mod->P = mod->U1d = mod->V1d = mod->Upi_1d = mod->Vpi_1d = NULL;
|
95
94
|
}
|
@@ -5,32 +5,35 @@
|
|
5
5
|
|
6
6
|
#include "patch.h"
|
7
7
|
|
8
|
-
void patch_init(patch_t* p, uint32_t U, uint32_t V, size_t row, size_t col) {
|
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
9
|
if (p == NULL) return;
|
10
10
|
p->row = row;
|
11
11
|
p->col = col;
|
12
12
|
|
13
13
|
p->U = U;
|
14
14
|
p->V = V;
|
15
|
-
p->U_pi = 0
|
16
|
-
p->V_pi = 0
|
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));
|
17
20
|
|
18
21
|
for (size_t i = 0; i < 4; i++) {
|
19
|
-
p->U_weight[i] = 0
|
20
|
-
p->V_weight[i] = 0
|
21
|
-
p->pi_death_rates[i] = 0
|
22
|
+
p->U_weight[i] = 0;
|
23
|
+
p->V_weight[i] = 0;
|
24
|
+
p->pi_death_rates[i] = 0;
|
22
25
|
}
|
23
26
|
for (size_t i = 0; i < 8; i++) {
|
24
|
-
p->mig_rates[i] = 0
|
27
|
+
p->mig_rates[i] = 0;
|
25
28
|
}
|
26
|
-
p->sum_U_weight = 0
|
27
|
-
p->sum_V_weight = 0
|
28
|
-
p->sum_pi_death_rates = 0
|
29
|
-
p->sum_mig_rates = 0
|
29
|
+
p->sum_U_weight = 0;
|
30
|
+
p->sum_V_weight = 0;
|
31
|
+
p->sum_pi_death_rates = 0;
|
32
|
+
p->sum_mig_rates = 0;
|
30
33
|
}
|
31
34
|
|
32
35
|
|
33
|
-
void set_nb(patch_t* world,
|
36
|
+
void set_nb(patch_t* world, size_t* nb_start, size_t ij, size_t NM) {
|
34
37
|
// nb_start is the where patch ij's neighbor indices start
|
35
38
|
size_t num_nb = 0;
|
36
39
|
for (size_t k = 0; k < 4; k++) {
|
@@ -42,6 +45,6 @@ void set_nb(patch_t* world, double* P_start, size_t* nb_start, size_t ij, size_t
|
|
42
45
|
world[ij].nb[k] = NULL;
|
43
46
|
}
|
44
47
|
}
|
45
|
-
|
46
|
-
|
48
|
+
world[ij].P[0] *= (0.25 * num_nb);
|
49
|
+
world[ij].P[1] *= (0.25 * num_nb);
|
47
50
|
}
|
@@ -10,7 +10,7 @@
|
|
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 {
|
@@ -22,6 +22,9 @@ typedef struct patch_t {
|
|
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 row, size_t col);
|
38
|
-
void set_nb(patch_t* world,
|
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
|
|
@@ -0,0 +1,77 @@
|
|
1
|
+
/**
|
2
|
+
* The Random Number Generation module
|
3
|
+
* Returns a random double in (0, 1) with 2^-53 resolution, 0 and 1 not included
|
4
|
+
*
|
5
|
+
* First initialize xoshiro256+ states with Splitmix64
|
6
|
+
* Then use xoshiro256+ for random number generation
|
7
|
+
*
|
8
|
+
* Referrence:
|
9
|
+
* xoshiro256++ code: https://prng.di.unimi.it
|
10
|
+
* Splitmix64 code: https://rosettacode.org/wiki/Pseudo-random_numbers/Splitmix64
|
11
|
+
*
|
12
|
+
*/
|
13
|
+
|
14
|
+
#include <stdint.h>
|
15
|
+
|
16
|
+
|
17
|
+
// resolution of random01 is 2^-53
|
18
|
+
// which is (about) the IEEE 754 double precision
|
19
|
+
#define MAX_53BIT (uint64_t) ((1ULL << 53) - 1)
|
20
|
+
#define RAND_DENOM 1.0 / ((double) (1ULL << 53))
|
21
|
+
// xor_state
|
22
|
+
static uint64_t xor_state[4];
|
23
|
+
static uint64_t splitmix64_state;
|
24
|
+
|
25
|
+
|
26
|
+
|
27
|
+
static inline uint64_t Splitmix64_rand() {
|
28
|
+
// used to seed PCG initial states
|
29
|
+
splitmix64_state += 0x9e3779b97f4a7c15ULL;
|
30
|
+
uint64_t z = splitmix64_state;
|
31
|
+
z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;
|
32
|
+
z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;
|
33
|
+
return z ^ (z >> 31);
|
34
|
+
}
|
35
|
+
|
36
|
+
|
37
|
+
static inline uint64_t rot23(const uint64_t x) {
|
38
|
+
// 23 and 64 - 23
|
39
|
+
// Not used here, part of xoshiro256++
|
40
|
+
return (x << 23) | (x >> 41);
|
41
|
+
}
|
42
|
+
|
43
|
+
|
44
|
+
static inline uint64_t rot45(const uint64_t x) {
|
45
|
+
// 45 and 64 - 45
|
46
|
+
return (x << 45) | (x >> 19);
|
47
|
+
}
|
48
|
+
|
49
|
+
|
50
|
+
static inline double random01() {
|
51
|
+
// return a random number in (0, 1) with 2^-53 resolution. 0 and 1 not included.
|
52
|
+
|
53
|
+
const uint64_t result = xor_state[0] + xor_state[3];
|
54
|
+
const uint64_t t = xor_state[1] << 17;
|
55
|
+
|
56
|
+
xor_state[2] ^= xor_state[0];
|
57
|
+
xor_state[3] ^= xor_state[1];
|
58
|
+
xor_state[1] ^= xor_state[2];
|
59
|
+
xor_state[0] ^= xor_state[3];
|
60
|
+
|
61
|
+
xor_state[2] ^= t;
|
62
|
+
xor_state[3] = rot45(xor_state[3]);
|
63
|
+
|
64
|
+
return ((double) (result & MAX_53BIT) + 0.5) * RAND_DENOM;
|
65
|
+
}
|
66
|
+
|
67
|
+
|
68
|
+
static inline void rand_init(const uint64_t seed) {
|
69
|
+
// initialize PCG random
|
70
|
+
splitmix64_state = seed;
|
71
|
+
for (int i = 0; i < 4; i++) {
|
72
|
+
xor_state[i] = Splitmix64_rand();
|
73
|
+
}
|
74
|
+
(void) random01();
|
75
|
+
}
|
76
|
+
|
77
|
+
|
@@ -81,7 +81,7 @@ static double single_init(const model_t* restrict mod, patch_t* restrict world,
|
|
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_out], mod->I[ij_out * 2], mod->I[ij_out * 2 + 1], i, j);
|
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
85
|
ij_out++;
|
86
86
|
}
|
87
87
|
}
|
@@ -107,21 +107,21 @@ static double single_init(const model_t* restrict mod, patch_t* restrict world,
|
|
107
107
|
|
108
108
|
// set nb pointers for patches
|
109
109
|
for (size_t ij = 0; ij < NM; ij++) {
|
110
|
-
set_nb(world, &
|
110
|
+
set_nb(world, &nb_indices[ij * 4], ij, NM);
|
111
111
|
}
|
112
112
|
|
113
113
|
//////// Begin Running ////////
|
114
114
|
|
115
115
|
// init payoff & natural death rates
|
116
116
|
for (size_t ij = 0; ij < N; ij++) {
|
117
|
-
update_pi_k(&world[ij]
|
117
|
+
update_pi_k(&world[ij]);
|
118
118
|
}
|
119
119
|
|
120
120
|
// init migration rates & store patch rates
|
121
121
|
ij_out = 0;
|
122
122
|
for (size_t i = 0; i < N; i++) {
|
123
123
|
for (size_t j = 0; j < M; j++) {
|
124
|
-
uint8_t mig_result = init_mig(&world[ij_out]
|
124
|
+
uint8_t mig_result = init_mig(&world[ij_out]); // init mig rates for all 4 directions
|
125
125
|
if (mig_result == SIM_OVERFLOW) {
|
126
126
|
return -1 * SIM_OVERFLOW;
|
127
127
|
}
|
@@ -144,7 +144,7 @@ static double single_init(const model_t* restrict mod, patch_t* restrict world,
|
|
144
144
|
|
145
145
|
// make signal
|
146
146
|
if (mod->boundary) {
|
147
|
-
make_signal_zero_flux(picked_p->i, picked_p->j, e0, sig_p);
|
147
|
+
make_signal_zero_flux(N, M, picked_p->i, picked_p->j, e0, sig_p);
|
148
148
|
} else {
|
149
149
|
make_signal_periodical(N, M, picked_p->i, picked_p->j, e0, sig_p);
|
150
150
|
}
|
@@ -164,7 +164,7 @@ static double single_init(const model_t* restrict mod, patch_t* restrict world,
|
|
164
164
|
// maxtime too small
|
165
165
|
return -1 * SMALL_MAXTIME;
|
166
166
|
}
|
167
|
-
|
167
|
+
|
168
168
|
// store data
|
169
169
|
if (time > mod->record_itv) {
|
170
170
|
size_t recod_idx = (size_t) (time / mod->record_itv);
|
@@ -194,24 +194,10 @@ static uint8_t single_test(model_t* restrict mod, char* message) {
|
|
194
194
|
size_t max_record = mod->max_record;
|
195
195
|
double record_itv = mod->record_itv;
|
196
196
|
bool boundary = mod->boundary;
|
197
|
-
double*
|
198
|
-
double*
|
199
|
-
double*
|
200
|
-
double*
|
201
|
-
double* Upi_1d = mod->Upi_1d;
|
202
|
-
double* Vpi_1d = mod->Vpi_1d;
|
203
|
-
|
204
|
-
// print progress
|
205
|
-
double one_progress = 0.0;
|
206
|
-
if (mod->print_pct != -1) {
|
207
|
-
one_progress = maxtime * mod->print_pct / 100.0;
|
208
|
-
fprintf(stdout, "\r ");
|
209
|
-
fprintf(stdout, "\r%s: 0 %%", message);
|
210
|
-
fflush(stdout);
|
211
|
-
} else {
|
212
|
-
one_progress = 2.0 * maxtime;
|
213
|
-
}
|
214
|
-
double current_progress = one_progress;
|
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;
|
215
201
|
|
216
202
|
// update sum of rates every 1e5 rounds
|
217
203
|
// many rates are updated each time, rather than re-calculated.
|
@@ -219,10 +205,17 @@ static uint8_t single_test(model_t* restrict mod, char* message) {
|
|
219
205
|
size_t curr_update_sum_round = 0; // current round
|
220
206
|
size_t update_sum_freq = UPDATE_SUM_ROUNDS_SM; // recalculate sum every this many rounds
|
221
207
|
|
222
|
-
//
|
208
|
+
// set make_signal function based on boundary conditions
|
209
|
+
void (*make_signal)(size_t, size_t, size_t, size_t, uint8_t, signal_t*);
|
210
|
+
if (mod->boundary) {
|
211
|
+
make_signal = &make_signal_zero_flux;
|
212
|
+
} else {
|
213
|
+
make_signal = &make_signal_periodical;
|
214
|
+
}
|
215
|
+
|
216
|
+
// core containers
|
223
217
|
patch_t* world = (patch_t*) calloc(NM, sizeof(patch_t));
|
224
218
|
size_t* nb_indices = (size_t*) calloc(NM * 4, sizeof(size_t));
|
225
|
-
|
226
219
|
double* patch_rates = (double*) calloc(NM, sizeof(double));
|
227
220
|
double* sum_rates_by_row = (double*) calloc(N, sizeof(double));
|
228
221
|
double sum_rates = 0;
|
@@ -230,6 +223,17 @@ static uint8_t single_test(model_t* restrict mod, char* message) {
|
|
230
223
|
signal_t signal;
|
231
224
|
patch_picked_t picked;
|
232
225
|
|
226
|
+
// print progress
|
227
|
+
double one_progress = one_progress = 2.0 * maxtime;
|
228
|
+
if (mod->print_pct != -1) {
|
229
|
+
one_progress = maxtime * mod->print_pct / 100.0;
|
230
|
+
fprintf(stdout, "\r ");
|
231
|
+
fprintf(stdout, "\r%s: 0 %%", message);
|
232
|
+
fflush(stdout);
|
233
|
+
}
|
234
|
+
double current_progress = one_progress;
|
235
|
+
|
236
|
+
// Call single_init. Initialize rates and run for 1 event
|
233
237
|
double time = single_init(mod, world, nb_indices, patch_rates, sum_rates_by_row, &sum_rates, &signal, &picked);
|
234
238
|
if (time == -1 * SMALL_MAXTIME) {
|
235
239
|
// time too small
|
@@ -251,9 +255,10 @@ static uint8_t single_test(model_t* restrict mod, char* message) {
|
|
251
255
|
size_t record_index = (size_t) (time / mod->record_itv);
|
252
256
|
double record_time = time - record_index * record_itv;
|
253
257
|
|
258
|
+
//////// while loop ////////
|
254
259
|
|
255
260
|
while (time < maxtime) {
|
256
|
-
|
261
|
+
|
257
262
|
// update sums and print progress
|
258
263
|
curr_update_sum_round++;
|
259
264
|
if (curr_update_sum_round > update_sum_freq) {
|
@@ -264,11 +269,14 @@ static uint8_t single_test(model_t* restrict mod, char* message) {
|
|
264
269
|
uint8_t curr_prog = (uint8_t)(time * 100 / maxtime);
|
265
270
|
if (curr_prog < 10) {
|
266
271
|
fprintf(stdout, "\r%s: %d %%", message, (int)(time * 100 / maxtime));
|
272
|
+
fflush(stdout);
|
267
273
|
} else {
|
268
274
|
fprintf(stdout, "\r%s: %d%%", message, (int)(time * 100 / maxtime));
|
275
|
+
fflush(stdout);
|
269
276
|
}
|
270
|
-
|
271
|
-
//
|
277
|
+
//fprintf(stdout, "\n99: %d, %d, %f, %f\n100: %d, %d, %f, %f\n",
|
278
|
+
//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]);
|
279
|
+
//fflush(stdout);
|
272
280
|
current_progress += one_progress;
|
273
281
|
}
|
274
282
|
|
@@ -315,8 +323,8 @@ static uint8_t single_test(model_t* restrict mod, char* message) {
|
|
315
323
|
sum_rates_by_row[si1] -= patch_rates[sij1];
|
316
324
|
sum_rates -= patch_rates[sij1];
|
317
325
|
|
318
|
-
update_pi_k(&world[sij1]
|
319
|
-
update_mig_just_rate(&world[sij1]
|
326
|
+
update_pi_k(&world[sij1]);
|
327
|
+
update_mig_just_rate(&world[sij1]);
|
320
328
|
|
321
329
|
patch_rates[sij1] = world[sij1].sum_pi_death_rates + world[sij1].sum_mig_rates;
|
322
330
|
sum_rates_by_row[si1] += patch_rates[sij1];
|
@@ -328,11 +336,11 @@ static uint8_t single_test(model_t* restrict mod, char* message) {
|
|
328
336
|
sum_rates -= patch_rates[sij1];
|
329
337
|
sum_rates -= patch_rates[sij2];
|
330
338
|
|
331
|
-
update_pi_k(&world[sij1]
|
332
|
-
update_pi_k(&world[sij2]
|
339
|
+
update_pi_k(&world[sij1]); // update both patches' payoffs first
|
340
|
+
update_pi_k(&world[sij2]);
|
333
341
|
|
334
|
-
if (update_mig_weight_rate(&world[sij1],
|
335
|
-
update_mig_weight_rate(&world[sij2],
|
342
|
+
if (update_mig_weight_rate(&world[sij1], rela_loc) == SIM_OVERFLOW ||
|
343
|
+
update_mig_weight_rate(&world[sij2], rela_loc ^ 1) == SIM_OVERFLOW) {
|
336
344
|
|
337
345
|
fprintf(stdout, "\nError: overflow at t = %f\n", time);
|
338
346
|
fflush(stdout);
|
@@ -354,7 +362,7 @@ static uint8_t single_test(model_t* restrict mod, char* message) {
|
|
354
362
|
size_t nb_idx = nb_indices[sij1 * 4 + k];
|
355
363
|
if (nb_idx == NM) { continue; } // invalid neighbor
|
356
364
|
// all neighbors, as long as exists, need to change
|
357
|
-
if (update_mig_weight_rate(&world[nb_idx],
|
365
|
+
if (update_mig_weight_rate(&world[nb_idx], k ^ 1) == SIM_OVERFLOW) {
|
358
366
|
fprintf(stdout, "\nError: overflow at t = %f\n", time);
|
359
367
|
fflush(stdout);
|
360
368
|
single_test_free(&world, &nb_indices, &patch_rates, &sum_rates_by_row);
|
@@ -369,7 +377,7 @@ static uint8_t single_test(model_t* restrict mod, char* message) {
|
|
369
377
|
if (nb_idx == NM) { continue; }
|
370
378
|
if (k != rela_loc) {
|
371
379
|
// nb_idx isn't the second last-changed patch
|
372
|
-
if (update_mig_weight_rate(&world[nb_idx],
|
380
|
+
if (update_mig_weight_rate(&world[nb_idx], k ^ 1) == SIM_OVERFLOW) {
|
373
381
|
fprintf(stdout, "\nError: overflow at t = %f\n", time);
|
374
382
|
fflush(stdout);
|
375
383
|
single_test_free(&world, &nb_indices, &patch_rates, &sum_rates_by_row);
|
@@ -383,7 +391,7 @@ static uint8_t single_test(model_t* restrict mod, char* message) {
|
|
383
391
|
if (nb_idx == NM) { continue; }
|
384
392
|
if (k != (rela_loc ^ 1)) {
|
385
393
|
// nb_idx isn't the first last-changed patch
|
386
|
-
if (update_mig_weight_rate(&world[nb_idx],
|
394
|
+
if (update_mig_weight_rate(&world[nb_idx], k ^ 1) == SIM_OVERFLOW) {
|
387
395
|
fprintf(stdout, "\nError: overflow at t = %f\n", time);
|
388
396
|
fflush(stdout);
|
389
397
|
single_test_free(&world, &nb_indices, &patch_rates, &sum_rates_by_row);
|
@@ -393,7 +401,6 @@ static uint8_t single_test(model_t* restrict mod, char* message) {
|
|
393
401
|
}
|
394
402
|
}
|
395
403
|
|
396
|
-
|
397
404
|
// pick a random event
|
398
405
|
double expected_sum = random01() * sum_rates;
|
399
406
|
find_patch(&picked, expected_sum, patch_rates, sum_rates_by_row, sum_rates, N, M);
|
@@ -407,13 +414,9 @@ static uint8_t single_test(model_t* restrict mod, char* message) {
|
|
407
414
|
}
|
408
415
|
|
409
416
|
// make signal
|
410
|
-
|
411
|
-
make_signal_zero_flux(picked.i, picked.j, e0, &signal);
|
412
|
-
} else {
|
413
|
-
make_signal_periodical(N, M, picked.i, picked.j, e0, &signal);
|
414
|
-
}
|
417
|
+
(*make_signal)(N, M, picked.i, picked.j, e0, &signal);
|
415
418
|
signal.ij1 = signal.i1 * M + signal.j1;
|
416
|
-
signal.ij2 = signal.i2 * M + signal.j2;
|
419
|
+
signal.ij2 = signal.i2 * M + signal.j2;
|
417
420
|
|
418
421
|
// let the event happenn
|
419
422
|
change_popu(&world[signal.ij1], signal.e1);
|
@@ -436,10 +439,10 @@ static uint8_t single_test(model_t* restrict mod, char* message) {
|
|
436
439
|
for (size_t ij = 0; ij < NM; ij++) {
|
437
440
|
size_t ij_max_record = ij * max_record;
|
438
441
|
for (size_t k = record_index; k < upper; k++) {
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
442
|
+
mod_U1d[ij_max_record + k] += world[ij].U;
|
443
|
+
mod_V1d[ij_max_record + k] += world[ij].V;
|
444
|
+
mod_Upi_1d[ij_max_record + k] += world[ij].U_pi;
|
445
|
+
mod_Vpi_1d[ij_max_record + k] += world[ij].V_pi;
|
443
446
|
}
|
444
447
|
}
|
445
448
|
record_index += multi_records;
|
@@ -450,10 +453,10 @@ static uint8_t single_test(model_t* restrict mod, char* message) {
|
|
450
453
|
for (size_t ij = 0; ij < NM; ij++) {
|
451
454
|
size_t ij_max_record = ij * max_record;
|
452
455
|
for (size_t k = record_index; k < max_record; k++) {
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
456
|
+
mod_U1d[ij_max_record + k] += world[ij].U;
|
457
|
+
mod_V1d[ij_max_record + k] += world[ij].V;
|
458
|
+
mod_Upi_1d[ij_max_record + k] += world[ij].U_pi;
|
459
|
+
mod_Vpi_1d[ij_max_record + k] += world[ij].V_pi;
|
457
460
|
}
|
458
461
|
}
|
459
462
|
}
|
@@ -500,40 +503,40 @@ uint8_t run(model_t* restrict mod, char* message, size_t msg_len) {
|
|
500
503
|
|
501
504
|
// initialize random
|
502
505
|
if (mod->seed != -1) {
|
503
|
-
|
504
|
-
} else {
|
505
|
-
srand(time(NULL));
|
506
|
-
}
|
507
|
-
|
508
|
-
if (mod->seed == -1){
|
509
|
-
srand(time(NULL));
|
506
|
+
rand_init((uint64_t) mod->seed);
|
510
507
|
} else {
|
511
|
-
|
508
|
+
rand_init((uint64_t) time(NULL));
|
512
509
|
}
|
513
510
|
|
514
511
|
if (mod->print_pct == 0) {
|
515
512
|
mod->print_pct = 5; // default print_pct
|
513
|
+
}
|
514
|
+
size_t print_round = 0; // print every some round if print_pct == x * 100, set to 0 for not printing
|
515
|
+
if (mod->print_pct >= 100) {
|
516
|
+
print_round = mod->print_pct / 100; // print progress every some round
|
517
|
+
mod->print_pct = -1; // not printing progress in single_test
|
516
518
|
}
|
517
519
|
|
518
|
-
size_t
|
520
|
+
size_t round = 0;
|
519
521
|
|
520
|
-
while (
|
522
|
+
while (round < mod->sim_time) {
|
521
523
|
char curr_msg[100 + msg_len]; // message for current round
|
522
524
|
strcpy(curr_msg, message);
|
523
525
|
strcat(curr_msg, "round ");
|
524
|
-
snprintf(curr_msg + strlen(curr_msg), sizeof(curr_msg) - strlen(curr_msg), "%zu",
|
526
|
+
snprintf(curr_msg + strlen(curr_msg), sizeof(curr_msg) - strlen(curr_msg), "%zu", round);
|
525
527
|
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
|
528
|
+
if ((print_round != 0) && (round % print_round == 0)) {
|
529
|
+
// only printing the round number
|
530
|
+
// add "!= 0" because round 0 could trigger printing
|
531
|
+
fprintf(stdout, "\r%s", curr_msg);
|
532
|
+
fflush(stdout);
|
533
|
+
}
|
531
534
|
|
532
535
|
uint8_t result = single_test(mod, curr_msg);
|
533
536
|
|
534
537
|
switch (result) {
|
535
538
|
case SUCCESS:
|
536
|
-
|
539
|
+
round++;
|
537
540
|
break;
|
538
541
|
case SMALL_MAXTIME:
|
539
542
|
// error message is handled by single_test
|
@@ -549,9 +552,9 @@ uint8_t run(model_t* restrict mod, char* message, size_t msg_len) {
|
|
549
552
|
|
550
553
|
calculate_ave(mod);
|
551
554
|
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
+
if ((mod->print_pct != -1) || (print_round != 0)) {
|
556
|
+
// print runtime if the original mod->print_pct != -1
|
557
|
+
double stop = clock();
|
555
558
|
fprintf(stdout, "\r%sruntime: %.3fs \n", message, (double)(stop - start) / CLOCKS_PER_SEC);
|
556
559
|
fflush(stdout);
|
557
560
|
}
|
@@ -15,11 +15,11 @@
|
|
15
15
|
|
16
16
|
#include "patch.h"
|
17
17
|
#include "model.h"
|
18
|
+
#include "random.h"
|
19
|
+
|
18
20
|
|
19
21
|
|
20
22
|
|
21
|
-
// upper bound for RNG is 2^30 + 1
|
22
|
-
#define RAND_UPPER_PLUS_2 (double) ((1LL << 30) + 1)
|
23
23
|
|
24
24
|
// directions of migration
|
25
25
|
// so that 3 - mig_dir = reflection of it. Used to track neighbors
|
@@ -55,8 +55,6 @@
|
|
55
55
|
#define UPDATE_SUM_ROUNDS_SM 100 // small, more frequent if some rate is larger than ACCURATE_BOUND
|
56
56
|
#define UPDATE_SUM_ROUNDS_LG 10000
|
57
57
|
|
58
|
-
|
59
|
-
|
60
58
|
|
61
59
|
/**
|
62
60
|
* index of patch in find_patch
|
@@ -105,42 +103,27 @@ uint8_t run(model_t* restrict mod, char* message, size_t msg_len);
|
|
105
103
|
|
106
104
|
|
107
105
|
|
108
|
-
/**
|
109
|
-
* Inline Functions
|
110
|
-
*/
|
111
|
-
|
112
|
-
static inline double random01() {
|
113
|
-
// generate a 24 bit random int, then convert to a (0, 1) ranged double
|
114
|
-
uint32_t r1 = rand() & 0x7fff; // RAND_MAX is different across machines, ensure 15 bits
|
115
|
-
uint32_t r2 = rand() & 0x7fff;
|
116
|
-
|
117
|
-
double r_combined = (r1 << 15) + r2;
|
118
|
-
return (r_combined + 1) / RAND_UPPER_PLUS_2;
|
119
|
-
}
|
120
|
-
|
121
106
|
/**
|
122
107
|
* patch functions
|
123
108
|
*/
|
124
109
|
|
125
|
-
static inline void update_pi_k(patch_t* restrict p
|
126
|
-
//
|
127
|
-
// P_start: start index of p's patch variables, i.e., ij * 6
|
128
|
-
|
110
|
+
static inline void update_pi_k(patch_t* restrict p) {
|
111
|
+
// update payoff and carrying capacity rates
|
129
112
|
uint32_t U = p->U;
|
130
113
|
uint32_t V = p->V;
|
131
114
|
double sum = U + V;
|
132
|
-
double U_ratio = U / sum;
|
133
|
-
double V_ratio = V / sum;
|
134
115
|
|
135
116
|
if (sum > 0) {
|
117
|
+
double U_ratio = U / sum;
|
118
|
+
double V_ratio = V / sum;
|
136
119
|
if (U > 0) {
|
137
|
-
p->U_pi = U_ratio *
|
120
|
+
p->U_pi = U_ratio * p->X[0] + V_ratio * p->X[1];
|
138
121
|
} else {
|
139
122
|
p->U_pi = 0.0;
|
140
123
|
}
|
141
124
|
|
142
125
|
if (V > 0) {
|
143
|
-
p->V_pi = U_ratio *
|
126
|
+
p->V_pi = U_ratio * p->X[2] + V_ratio * p->X[3];
|
144
127
|
} else {
|
145
128
|
p->V_pi = 0.0;
|
146
129
|
}
|
@@ -153,8 +136,8 @@ static inline void update_pi_k(patch_t* restrict p, const double* restrict M_sta
|
|
153
136
|
p->pi_death_rates[0] = fabs(U * p->U_pi);
|
154
137
|
p->pi_death_rates[1] = fabs(V * p->V_pi);
|
155
138
|
|
156
|
-
p->pi_death_rates[2] =
|
157
|
-
p->pi_death_rates[3] =
|
139
|
+
p->pi_death_rates[2] = p->P[4] * U * sum;
|
140
|
+
p->pi_death_rates[3] = p->P[5] * V * sum;
|
158
141
|
|
159
142
|
p->sum_pi_death_rates = 0.0;
|
160
143
|
for (size_t i = 0; i < 4; i++) {
|
@@ -164,14 +147,14 @@ static inline void update_pi_k(patch_t* restrict p, const double* restrict M_sta
|
|
164
147
|
|
165
148
|
|
166
149
|
|
167
|
-
static inline void update_mig_just_rate(patch_t* restrict p
|
150
|
+
static inline void update_mig_just_rate(patch_t* restrict p) {
|
168
151
|
// update migration weight for patch p, in location loc. Only rate is updated
|
169
152
|
// used by last-changed patch, when there is only one last-changed patch
|
170
153
|
double* p_U_weight = p->U_weight;
|
171
154
|
double* p_V_weight = p->V_weight;
|
172
155
|
|
173
|
-
double mu1_U =
|
174
|
-
double mu2_V =
|
156
|
+
double mu1_U = p->P[0] * p->U;
|
157
|
+
double mu2_V = p->P[1] * p->V;
|
175
158
|
|
176
159
|
double mu1_U_divide_sum = mu1_U / p->sum_U_weight;
|
177
160
|
double mu2_V_divide_sum = mu2_V / p->sum_V_weight;
|
@@ -184,7 +167,7 @@ static inline void update_mig_just_rate(patch_t* restrict p, const double* restr
|
|
184
167
|
}
|
185
168
|
|
186
169
|
|
187
|
-
static inline uint8_t update_mig_weight_rate(patch_t* restrict p, const
|
170
|
+
static inline uint8_t update_mig_weight_rate(patch_t* restrict p, const uint8_t loc) {
|
188
171
|
// update migration weight as well as rates, in one direction
|
189
172
|
// used by neighbors of last-changed patches
|
190
173
|
// also used by last-changed patches themselve, when there are two patch changed, to update mig rates of in each other's direction
|
@@ -196,8 +179,8 @@ static inline uint8_t update_mig_weight_rate(patch_t* restrict p, const double*
|
|
196
179
|
p->sum_U_weight -= p_U_weight[loc];
|
197
180
|
p->sum_V_weight -= p_V_weight[loc];
|
198
181
|
|
199
|
-
double w1_Upi =
|
200
|
-
double w2_Vpi =
|
182
|
+
double w1_Upi = p->P[2] * nbi->U_pi;
|
183
|
+
double w2_Vpi = p->P[3] * nbi->V_pi;
|
201
184
|
if (w1_Upi > EXP_OVERFLOW_BOUND) {
|
202
185
|
return SIM_OVERFLOW;
|
203
186
|
}
|
@@ -226,8 +209,8 @@ static inline uint8_t update_mig_weight_rate(patch_t* restrict p, const double*
|
|
226
209
|
p->sum_U_weight += p_U_weight[loc];
|
227
210
|
p->sum_V_weight += p_V_weight[loc];
|
228
211
|
|
229
|
-
double mu1_U =
|
230
|
-
double mu2_V =
|
212
|
+
double mu1_U = p->P[0] * p->U;
|
213
|
+
double mu2_V = p->P[1] * p->V;
|
231
214
|
double mu1_U_divide_sum = mu1_U / p->sum_U_weight;
|
232
215
|
double mu2_V_divide_sum = mu2_V / p->sum_V_weight;
|
233
216
|
|
@@ -242,7 +225,7 @@ static inline uint8_t update_mig_weight_rate(patch_t* restrict p, const double*
|
|
242
225
|
|
243
226
|
|
244
227
|
|
245
|
-
static inline uint8_t init_mig(patch_t* restrict p
|
228
|
+
static inline uint8_t init_mig(patch_t* restrict p) {
|
246
229
|
// update migration rate for all directions
|
247
230
|
|
248
231
|
double* p_U_weight = p->U_weight;
|
@@ -251,8 +234,8 @@ static inline uint8_t init_mig(patch_t* restrict p, const double* restrict P_sta
|
|
251
234
|
p->sum_U_weight = 0.0;
|
252
235
|
p->sum_V_weight = 0.0;
|
253
236
|
|
254
|
-
double w1 =
|
255
|
-
double w2 =
|
237
|
+
double w1 = p->P[2];
|
238
|
+
double w2 = p->P[3];
|
256
239
|
|
257
240
|
for (uint8_t i = 0; i < 4; i++) {
|
258
241
|
patch_t* nbi = p->nb[i];
|
@@ -274,8 +257,8 @@ static inline uint8_t init_mig(patch_t* restrict p, const double* restrict P_sta
|
|
274
257
|
}
|
275
258
|
}
|
276
259
|
|
277
|
-
double mu1_U =
|
278
|
-
double mu2_V =
|
260
|
+
double mu1_U = p->P[0] * p->U;
|
261
|
+
double mu2_V = p->P[1] * p->V;
|
279
262
|
double mu1_U_divide_sum = mu1_U / p->sum_U_weight;
|
280
263
|
double mu2_V_divide_sum = mu2_V / p->sum_V_weight;
|
281
264
|
|
@@ -290,7 +273,7 @@ static inline uint8_t init_mig(patch_t* restrict p, const double* restrict P_sta
|
|
290
273
|
|
291
274
|
|
292
275
|
|
293
|
-
static inline uint8_t find_event(const patch_t* restrict p, double expected_sum) {
|
276
|
+
static inline uint8_t find_event(const patch_t* restrict p, const double expected_sum) {
|
294
277
|
size_t event = 0;
|
295
278
|
double current_sum;
|
296
279
|
|
@@ -320,7 +303,7 @@ static inline uint8_t find_event(const patch_t* restrict p, double expected_sum)
|
|
320
303
|
}
|
321
304
|
|
322
305
|
|
323
|
-
static inline void change_popu(patch_t* restrict p, uint8_t s) {
|
306
|
+
static inline void change_popu(patch_t* restrict p, const uint8_t s) {
|
324
307
|
switch (s) {
|
325
308
|
case 0:
|
326
309
|
// Migration IN for U
|
@@ -362,11 +345,12 @@ static inline void change_popu(patch_t* restrict p, uint8_t s) {
|
|
362
345
|
* Main Simulation Functions
|
363
346
|
*/
|
364
347
|
|
365
|
-
static inline void find_patch(patch_picked_t* restrict picked, double expected_sum,
|
366
|
-
const double* restrict patch_rates, const double* restrict sum_rates_by_row, double sum_rates, size_t N, size_t M) {
|
348
|
+
static inline void find_patch(patch_picked_t* restrict picked, const double expected_sum,
|
349
|
+
const double* restrict patch_rates, const double* restrict sum_rates_by_row, const double sum_rates, const size_t N, const size_t M) {
|
367
350
|
double current_sum = 0;
|
368
351
|
size_t row = 0;
|
369
352
|
size_t col = 0;
|
353
|
+
size_t row_M = 0;
|
370
354
|
|
371
355
|
// Find row
|
372
356
|
if (N != 1) {
|
@@ -388,10 +372,9 @@ static inline void find_patch(patch_picked_t* restrict picked, double expected_s
|
|
388
372
|
}
|
389
373
|
row++;
|
390
374
|
}
|
375
|
+
row_M = row * M;
|
391
376
|
}
|
392
377
|
|
393
|
-
size_t row_M = row * M;
|
394
|
-
|
395
378
|
// Find col in that row
|
396
379
|
if ((expected_sum - current_sum) < sum_rates_by_row[row] * 0.5) {
|
397
380
|
col = 0;
|
@@ -418,7 +401,10 @@ static inline void find_patch(patch_picked_t* restrict picked, double expected_s
|
|
418
401
|
|
419
402
|
|
420
403
|
|
421
|
-
static inline void make_signal_zero_flux(size_t i, size_t j, uint8_t e, signal_t* restrict signal) {
|
404
|
+
static inline void make_signal_zero_flux(const size_t N, const size_t M, const size_t i, const size_t j, const uint8_t e, signal_t* restrict signal) {
|
405
|
+
// pass in N & M as well to match the param set of make_signal_periodical
|
406
|
+
(void) N;
|
407
|
+
(void) M;
|
422
408
|
// this is always the case for the first one
|
423
409
|
signal->i1 = i;
|
424
410
|
signal->j1 = j;
|
@@ -496,15 +482,12 @@ static inline void make_signal_zero_flux(size_t i, size_t j, uint8_t e, signal_t
|
|
496
482
|
signal->e2 = 3;
|
497
483
|
signal->rela_loc = MIG_RIGHT;
|
498
484
|
return;
|
499
|
-
//default:
|
500
|
-
// fprintf(stderr, "Bug: invalid case in make_signal_zf, i, j, e: %zu, %zu, %hhu\n", i, j, e);
|
501
|
-
// return;
|
502
485
|
}
|
503
486
|
}
|
504
487
|
|
505
488
|
|
506
489
|
|
507
|
-
static inline void make_signal_periodical(size_t N, size_t M, size_t i, size_t j, uint8_t e, signal_t* restrict signal) {
|
490
|
+
static inline void make_signal_periodical(const size_t N, const size_t M, const size_t i, const size_t j, const uint8_t e, signal_t* restrict signal) {
|
508
491
|
// this is always the case for the first one
|
509
492
|
signal->i1 = i;
|
510
493
|
signal->j1 = j;
|
@@ -582,9 +565,6 @@ static inline void make_signal_periodical(size_t N, size_t M, size_t i, size_t j
|
|
582
565
|
signal->e2 = 3;
|
583
566
|
signal->rela_loc = MIG_RIGHT;
|
584
567
|
return;
|
585
|
-
//default:
|
586
|
-
// fprintf(stderr, "Bug: invalid case in make_signal_pr, i, j, e: %zu, %zu, %hhu\n", i, j, e);
|
587
|
-
// return;
|
588
568
|
}
|
589
569
|
}
|
590
570
|
|
@@ -23,7 +23,7 @@ from .build_info import build_info
|
|
23
23
|
|
24
24
|
from .simulation import model, run, demo_model, UV_expected_val, check_overflow_func
|
25
25
|
from .videos import make_video, SUPPORTED_FIGURES
|
26
|
-
from .data_tools import
|
26
|
+
from .data_tools import save, load
|
27
27
|
|
28
28
|
from .analysis import rounds_expected, scale_maxtime, check_convergence, combine_sim
|
29
29
|
|
@@ -38,7 +38,7 @@ simulation_memebers = ['model', 'run', 'demo_model']
|
|
38
38
|
|
39
39
|
videos_members = ['make_video', 'SUPPORTED_FIGURES']
|
40
40
|
|
41
|
-
data_members = ['
|
41
|
+
data_members = ['save', 'load']
|
42
42
|
|
43
43
|
analysis_members = ['expected_rounds', 'scale_maxtime', 'check_convergence', 'combine_mod']
|
44
44
|
|
@@ -1,4 +1,4 @@
|
|
1
|
-
__version__ = '2.3.
|
1
|
+
__version__ = '2.3.9'
|
2
2
|
|
3
3
|
'''
|
4
4
|
version history:
|
@@ -44,4 +44,6 @@ version history:
|
|
44
44
|
2.3.5: improved accuracy for simulation, now can better handle large mig rates. Numerical errors are now being checked and reduced automatically based on how large the values are.
|
45
45
|
2.3.6: index error due to reduced accuracy is now explicitly handled.
|
46
46
|
2.3.7: update migration rules on the boundary. mu values are scaled based on how many neighbors a patch has. Minor debugging in several modules.
|
47
|
+
2.3.8: bug fix for 2.3.7 update.
|
48
|
+
2.3.9: now use xoshiro256+ as RNG.
|
47
49
|
'''
|
@@ -2,8 +2,8 @@
|
|
2
2
|
Stores and reads a model object.
|
3
3
|
|
4
4
|
Functions:
|
5
|
-
-
|
6
|
-
-
|
5
|
+
- save: save a model object.
|
6
|
+
- load: load a model object.
|
7
7
|
'''
|
8
8
|
|
9
9
|
|
@@ -12,9 +12,10 @@ from . import simulation
|
|
12
12
|
import json
|
13
13
|
import gzip
|
14
14
|
import os
|
15
|
+
import numpy as np
|
15
16
|
|
16
17
|
|
17
|
-
def
|
18
|
+
def save(mod, dirs = '', print_msg = True):
|
18
19
|
'''
|
19
20
|
Saves a model object. Data will be stored at dirs/data.json.gz
|
20
21
|
|
@@ -46,7 +47,6 @@ def save_data(mod, dirs = '', print_msg = True):
|
|
46
47
|
inputs.append(mod.P.tolist())
|
47
48
|
inputs.append(mod.print_pct)
|
48
49
|
inputs.append(mod.seed)
|
49
|
-
inputs.append(mod.check_overflow)
|
50
50
|
data.append(inputs)
|
51
51
|
|
52
52
|
# skipped rng
|
@@ -54,11 +54,17 @@ def save_data(mod, dirs = '', print_msg = True):
|
|
54
54
|
outputs = []
|
55
55
|
outputs.append(mod.max_record)
|
56
56
|
outputs.append(mod.compress_itv)
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
57
|
+
if not mod.data_empty:
|
58
|
+
outputs.append(mod.U.tolist())
|
59
|
+
outputs.append(mod.V.tolist())
|
60
|
+
outputs.append(mod.Upi.tolist())
|
61
|
+
outputs.append(mod.Vpi.tolist())
|
62
|
+
else:
|
63
|
+
outputs.append(None)
|
64
|
+
outputs.append(None)
|
65
|
+
outputs.append(None)
|
66
|
+
outputs.append(None)
|
67
|
+
|
62
68
|
data.append(outputs)
|
63
69
|
|
64
70
|
data_dirs = os.path.join(dirs, 'data.json.gz')
|
@@ -70,7 +76,7 @@ def save_data(mod, dirs = '', print_msg = True):
|
|
70
76
|
|
71
77
|
|
72
78
|
|
73
|
-
def
|
79
|
+
def load(dirs):
|
74
80
|
'''
|
75
81
|
Reads and returns a model object.
|
76
82
|
|
@@ -96,16 +102,19 @@ def read_data(dirs):
|
|
96
102
|
try:
|
97
103
|
mod = simulation.model(N = data[0][0], M = data[0][1], maxtime = data[0][2], record_itv = data[0][3],
|
98
104
|
sim_time = data[0][4], boundary = data[0][5], I = data[0][6], X = data[0][7], P = data[0][8],
|
99
|
-
print_pct = data[0][9], seed = data[0][10], check_overflow =
|
105
|
+
print_pct = data[0][9], seed = data[0][10], check_overflow = False)
|
100
106
|
except:
|
101
|
-
raise ValueError('Invalid input parameters
|
107
|
+
raise ValueError('Invalid input parameters stored in data')
|
102
108
|
|
103
109
|
# outputs
|
104
110
|
try:
|
105
111
|
mod.set_data(data_empty = False, max_record = data[1][0], compress_itv = data[1][1],
|
106
112
|
U = data[1][2], V = data[1][3], Upi = data[1][4], Vpi = data[1][5])
|
113
|
+
if (mod.U is None) or (isinstance(mod.U, np.ndarray) and mod.U.shape == () and mod.U.item() is None):
|
114
|
+
# if data is None
|
115
|
+
mod.data_empty = True
|
107
116
|
except:
|
108
|
-
raise ValueError('Invalid
|
117
|
+
raise ValueError('Invalid simulation results stored in data')
|
109
118
|
|
110
119
|
return mod
|
111
120
|
|
@@ -164,22 +164,11 @@ class model:
|
|
164
164
|
if check_overflow:
|
165
165
|
check_overflow_func(self)
|
166
166
|
|
167
|
-
|
168
|
-
|
167
|
+
# initialize storage bins.
|
168
|
+
self.set_data(data_empty = True, max_record = int(maxtime / record_itv), compress_itv = 1,
|
169
|
+
U = None, V = None, Upi = None, Vpi = None)
|
169
170
|
|
170
171
|
|
171
|
-
def init_storage(self):
|
172
|
-
# initialize storage bins
|
173
|
-
self.data_empty = True # whether data storage bins are empty. model.run will refuse to run (raise error) if not empty.
|
174
|
-
self.max_record = int(self.maxtime / self.record_itv) # int, how many data points to store sin total
|
175
|
-
self.compress_itv = 1 # int, intended to reduce size of data (if not 1). Updated by compress_data function
|
176
|
-
# if set to an int, say 20, mod will take average over every 20 data points and save them as new data.
|
177
|
-
# May be used over and over again to recursively reduce data size.
|
178
|
-
# Default is 1, not to take average.
|
179
|
-
self.U = None # initialized by simulation.run or data_tools.read_data
|
180
|
-
self.V = None
|
181
|
-
self.Upi = None
|
182
|
-
self.Vpi = None
|
183
172
|
|
184
173
|
|
185
174
|
def check_valid_input(self, N, M, maxtime, record_itv, sim_time, boundary, I, X, P, print_pct, seed, check_overflow):
|
@@ -319,6 +308,8 @@ class model:
|
|
319
308
|
|
320
309
|
if copy_data:
|
321
310
|
# copy data as well
|
311
|
+
if self.data_empty:
|
312
|
+
print("Warning: model has empty data")
|
322
313
|
sim2.set_data(self.data_empty, self.max_record, self.compress_itv, self.U, self.V, self.Upi, self.Vpi)
|
323
314
|
|
324
315
|
return sim2
|
@@ -426,10 +417,10 @@ def run(mod, message = ""):
|
|
426
417
|
P = np.ascontiguousarray(mod.P.flatten(), dtype = np.float64)
|
427
418
|
|
428
419
|
mod_c = model_c()
|
429
|
-
|
420
|
+
init_sucess = LIB.mod_init(ctypes.byref(mod_c),
|
430
421
|
mod.N, mod.M, mod.maxtime, mod.record_itv, mod.sim_time, mod.boundary,
|
431
422
|
I, X, P, mod.print_pct, mod.seed)
|
432
|
-
if not
|
423
|
+
if not init_sucess:
|
433
424
|
LIB.mod_free_py(ctypes.byref(mod_c))
|
434
425
|
del mod_c
|
435
426
|
raise RuntimeError('Model initialization failed')
|
@@ -93,7 +93,13 @@ class patch:
|
|
93
93
|
def set_nb_pointers(self, nb):
|
94
94
|
# nb is a list of pointers (point to patches)
|
95
95
|
# nb is passed from the model class
|
96
|
+
nb_count = 0
|
97
|
+
for nb_i in nb:
|
98
|
+
if nb_i != None:
|
99
|
+
nb_count += 1
|
96
100
|
self.nb = nb
|
101
|
+
self.mu1 *= (0.25 * nb_count)
|
102
|
+
self.mu2 *= (0.25 * nb_count)
|
97
103
|
|
98
104
|
|
99
105
|
def update_pi_k(self):
|
@@ -101,19 +107,21 @@ class patch:
|
|
101
107
|
|
102
108
|
U = self.U # bring the values to front
|
103
109
|
V = self.V
|
104
|
-
|
110
|
+
sum_UV = U + V # this value is used several times
|
105
111
|
|
106
|
-
if
|
112
|
+
if sum_UV > 0:
|
107
113
|
# interaction happens only if there is more than 1 individual
|
114
|
+
U_ratio = U / sum_UV
|
115
|
+
V_ratio = V / sum_UV
|
108
116
|
|
109
117
|
if U != 0:
|
110
118
|
# no payoff if U == 0
|
111
|
-
self.Upi =
|
119
|
+
self.Upi = U_ratio * self.matrix[0] + V_ratio * self.matrix[1]
|
112
120
|
else:
|
113
121
|
self.Upi = 0
|
114
122
|
|
115
123
|
if V != 0:
|
116
|
-
self.Vpi =
|
124
|
+
self.Vpi = U_ratio * self.matrix[2] + V_ratio * self.matrix[3]
|
117
125
|
else:
|
118
126
|
self.Vpi = 0
|
119
127
|
|
@@ -127,8 +135,8 @@ class patch:
|
|
127
135
|
self.pi_death_rates[1] = abs(V * self.Vpi)
|
128
136
|
|
129
137
|
# update natural death rates
|
130
|
-
self.pi_death_rates[2] = self.kappa1 * U *
|
131
|
-
self.pi_death_rates[3] = self.kappa2 * V *
|
138
|
+
self.pi_death_rates[2] = self.kappa1 * U * sum_UV
|
139
|
+
self.pi_death_rates[3] = self.kappa2 * V * sum_UV
|
132
140
|
|
133
141
|
# update sum of rates
|
134
142
|
self.sum_pi_death_rates = sum(self.pi_death_rates)
|
@@ -143,8 +151,8 @@ class patch:
|
|
143
151
|
|
144
152
|
for i in range(4):
|
145
153
|
if self.nb[i] != None:
|
146
|
-
U_weight[i] =
|
147
|
-
V_weight[i] =
|
154
|
+
U_weight[i] = pow(math.e, self.w1 * self.nb[i].Upi)
|
155
|
+
V_weight[i] = pow(math.e, self.w2 * self.nb[i].Vpi)
|
148
156
|
|
149
157
|
mu1_U = self.mu1 * self.U
|
150
158
|
mu2_V = self.mu2 * self.V
|
@@ -746,7 +754,7 @@ def single_test(mod, front_info, end_info, update_sum_frequency, rng):
|
|
746
754
|
|
747
755
|
|
748
756
|
|
749
|
-
def
|
757
|
+
def run(mod, predict_runtime = False, message = ''):
|
750
758
|
'''
|
751
759
|
Main function. Recursively calls single_test to run many models and then takes the average.
|
752
760
|
|
@@ -91,7 +91,7 @@ def test_var1(mod, var, values, dirs, compress_itv = None):
|
|
91
91
|
simulation.run(sim2, message = current_var_str + ', ')
|
92
92
|
if compress_itv != None:
|
93
93
|
sim2.compress_data(compress_itv)
|
94
|
-
data_t.
|
94
|
+
data_t.save(sim2, var_dirs[k], print_msg = False)
|
95
95
|
del sim2
|
96
96
|
except (OverflowError, RuntimeError):
|
97
97
|
print(current_var_str + ' raised error, skipped')
|
@@ -139,7 +139,7 @@ def test_var2(mod, var1, var2, values1, values2, dirs, compress_itv = None):
|
|
139
139
|
simulation.run(sim2, message = current_var_str + ', ')
|
140
140
|
if compress_itv != None:
|
141
141
|
sim2.compress_data(compress_itv)
|
142
|
-
data_t.
|
142
|
+
data_t.save(sim2, var_dirs[k1][k2], print_msg = False)
|
143
143
|
del sim2
|
144
144
|
except (OverflowError, RuntimeError):
|
145
145
|
print(current_var_str + ' raised error, skipped')
|
@@ -175,7 +175,7 @@ def var_UV1(var, values, var_dirs, ax_U = None, ax_V = None, start = 0.95, end =
|
|
175
175
|
|
176
176
|
for k in range(len(var_dirs)):
|
177
177
|
try:
|
178
|
-
simk = data_t.
|
178
|
+
simk = data_t.load(var_dirs[k])
|
179
179
|
except FileNotFoundError:
|
180
180
|
print(var + '=' + str(values[k]) + ' not found, skipped')
|
181
181
|
U_ave.append(None)
|
@@ -244,7 +244,7 @@ def var_UV2(var1, var2, values1, values2, var_dirs, ax_U = None, ax_V = None, va
|
|
244
244
|
for k1 in range(len(var_dirs)):
|
245
245
|
for k2 in range(len(var_dirs[k1])):
|
246
246
|
try:
|
247
|
-
simk = data_t.
|
247
|
+
simk = data_t.load(var_dirs[k1][k2])
|
248
248
|
except FileNotFoundError:
|
249
249
|
print(var1 + '=' + str(values1[k1]) + ', ' + var2 + '=' + str(values2[k2]) + ' not found, skipped')
|
250
250
|
U_ave[k1].append(None)
|
@@ -332,7 +332,7 @@ def var_pi1(var, values, var_dirs, ax_U = None, ax_V = None, start = 0.95, end =
|
|
332
332
|
|
333
333
|
for k in range(len(var_dirs)):
|
334
334
|
try:
|
335
|
-
simk = data_t.
|
335
|
+
simk = data_t.load(var_dirs[k])
|
336
336
|
except FileNotFoundError:
|
337
337
|
print(var + '=' + str(values[k]) + ' not found, skipped')
|
338
338
|
U_ave.append(None)
|
@@ -397,7 +397,7 @@ def var_pi2(var1, var2, values1, values2, var_dirs, ax_U = None, ax_V = None, va
|
|
397
397
|
for k1 in range(len(var_dirs)):
|
398
398
|
for k2 in range(len(var_dirs[k1])):
|
399
399
|
try:
|
400
|
-
simk = data_t.
|
400
|
+
simk = data_t.load(var_dirs[k1][k2])
|
401
401
|
except FileNotFoundError:
|
402
402
|
print(var1 + '=' + str(values1[k1]) + ', ' + var2 + '=' + str(values2[k2]) + ' not found, skipped')
|
403
403
|
U_ave[k1].append(None)
|
@@ -512,7 +512,7 @@ def var_convergence1(var_dirs, interval = 20, start = 0.8, fluc = 0.07):
|
|
512
512
|
for k in range(len(var_dirs)):
|
513
513
|
dirs = var_dirs[k]
|
514
514
|
try:
|
515
|
-
simk = data_t.
|
515
|
+
simk = data_t.load(dirs)
|
516
516
|
except FileNotFoundError:
|
517
517
|
print(dirs + ' data not found, skipped')
|
518
518
|
continue
|
@@ -581,7 +581,7 @@ def var_convergence2(var_dirs, interval = 20, start = 0.8, fluc = 0.07):
|
|
581
581
|
for k in range(len(sublist)):
|
582
582
|
dirs = sublist[k]
|
583
583
|
try:
|
584
|
-
simk = data_t.
|
584
|
+
simk = data_t.load(dirs)
|
585
585
|
except FileNotFoundError:
|
586
586
|
print(dirs + ' data not found, skipped')
|
587
587
|
continue
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|