piegy 2.1.0__cp38-cp38-win32.whl → 2.1.9__cp38-cp38-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.cp38-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 +1 -0
- piegy/__version__.py +3 -1
- piegy/build_info.py +12 -0
- piegy/find_C.py +17 -0
- piegy/simulation.py +29 -20
- piegy/simulation_py.py +1 -2
- {piegy-2.1.0.dist-info → piegy-2.1.9.dist-info}/METADATA +2 -2
- piegy-2.1.9.dist-info/RECORD +29 -0
- piegy-2.1.0.dist-info/RECORD +0 -18
- {piegy-2.1.0.dist-info → piegy-2.1.9.dist-info}/LICENSE.txt +0 -0
- {piegy-2.1.0.dist-info → piegy-2.1.9.dist-info}/WHEEL +0 -0
- {piegy-2.1.0.dist-info → piegy-2.1.9.dist-info}/top_level.txt +0 -0
piegy/C_core/sim_funcs.h
ADDED
@@ -0,0 +1,547 @@
|
|
1
|
+
/**
|
2
|
+
* This .h defines the simulation functions in piegy.simulation
|
3
|
+
*/
|
4
|
+
|
5
|
+
#ifndef SIM_FUNCS
|
6
|
+
#define SIM_FUNCS
|
7
|
+
|
8
|
+
#include <stdlib.h>
|
9
|
+
#include <stdint.h>
|
10
|
+
#include <stdio.h>
|
11
|
+
#include <stdbool.h>
|
12
|
+
#include <string.h>
|
13
|
+
#include <time.h>
|
14
|
+
#include <math.h>
|
15
|
+
|
16
|
+
#include "patch.h"
|
17
|
+
#include "model.h"
|
18
|
+
|
19
|
+
|
20
|
+
|
21
|
+
// upper bound for RNG is 2^24 + 1
|
22
|
+
#define RAND_UPPER_PLUS_2 (double) (0xffffffu + 2)
|
23
|
+
|
24
|
+
// directions of migration
|
25
|
+
// so that 3 - mig_dir = reflection of it. Used to track neighbors
|
26
|
+
// the actual implementation of signals still uses this order: up, down, left, right
|
27
|
+
#define MIG_UP 0
|
28
|
+
#define MIG_DOWN 1
|
29
|
+
#define MIG_LEFT 2
|
30
|
+
#define MIG_RIGHT 3
|
31
|
+
|
32
|
+
// results of single_test
|
33
|
+
#define SUCCESS 0
|
34
|
+
#define GENERAL_FAILURE 1
|
35
|
+
#define SMALL_MAXTIME 2
|
36
|
+
#define OVERFLOW 3
|
37
|
+
|
38
|
+
// where exp(x) reaches overflow bound (just below it)
|
39
|
+
#define EXP_OVERFLOW_BOUND 700
|
40
|
+
|
41
|
+
|
42
|
+
static uint64_t pcg_state = 0;
|
43
|
+
static uint64_t pcg_inc = 0;
|
44
|
+
|
45
|
+
|
46
|
+
|
47
|
+
|
48
|
+
/**
|
49
|
+
* index of patch in find_patch
|
50
|
+
*/
|
51
|
+
typedef struct patch_picked_t {
|
52
|
+
size_t i;
|
53
|
+
size_t j;
|
54
|
+
double current_sum;
|
55
|
+
} patch_picked_t;
|
56
|
+
|
57
|
+
/**
|
58
|
+
* index & event number in make_signal_*
|
59
|
+
*/
|
60
|
+
typedef struct signal_t {
|
61
|
+
// does the signal only have the first patch?
|
62
|
+
bool only_first;
|
63
|
+
|
64
|
+
// the first patch
|
65
|
+
size_t i1;
|
66
|
+
size_t j1;
|
67
|
+
size_t ij1; // i1 * M + j1
|
68
|
+
uint8_t e1;
|
69
|
+
|
70
|
+
// the second patch
|
71
|
+
size_t i2;
|
72
|
+
size_t j2;
|
73
|
+
size_t ij2;
|
74
|
+
uint8_t e2;
|
75
|
+
} signal_t;
|
76
|
+
|
77
|
+
|
78
|
+
|
79
|
+
/**
|
80
|
+
* Defined in .c
|
81
|
+
*/
|
82
|
+
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);
|
83
|
+
static void find_nb_periodical(size_t* restrict nb, size_t i, size_t j, size_t N, size_t M, size_t NM);
|
84
|
+
static double single_init(const model_t* mod, patch_t* world, size_t* nb_indices,
|
85
|
+
double* patch_rates, double* sum_rates_by_row, double* sum_rates, signal_t* sig_p, patch_picked_t* picked_p) ;
|
86
|
+
static void single_test(model_t* restrict mod, uint32_t update_sum_frequency, uint32_t* result, char* message);
|
87
|
+
static void single_test_free(patch_t* world, size_t* nb_indices, double* patch_rates, double* sum_rates_by_row);
|
88
|
+
void run(model_t* mod, char* message, size_t msg_len);
|
89
|
+
|
90
|
+
|
91
|
+
/**
|
92
|
+
* Inline Functions
|
93
|
+
*/
|
94
|
+
|
95
|
+
static inline double random01() {
|
96
|
+
// generate a 24 bit random int, then convert to a (0, 1) ranged double
|
97
|
+
uint32_t r1 = rand() & 0x7fff; // RAND_MAX is different across machines, ensure 15 bits
|
98
|
+
uint32_t r2 = rand() & 0x7fff;
|
99
|
+
|
100
|
+
double r_combined = ((r1 >> 3) << 12) + (r2 >> 3); // discard the lower 3 bits, which are unstable
|
101
|
+
return (r_combined + 1) / RAND_UPPER_PLUS_2;
|
102
|
+
}
|
103
|
+
|
104
|
+
/**
|
105
|
+
* patch functions
|
106
|
+
*/
|
107
|
+
|
108
|
+
static inline void update_pi_k(patch_t* restrict p, const double* restrict M_start, const double* restrict P_kappa_start) {
|
109
|
+
// M_start: start index of patch (i, j)'s matrix
|
110
|
+
// P_kappa_start: start index of patch (i, j)'s kappa values (the 4th and 5th, 0-indexed)
|
111
|
+
|
112
|
+
double U = (double) p->U;
|
113
|
+
double V = (double) p->V;
|
114
|
+
double sum_minus_1 = U + V - 1.0;
|
115
|
+
|
116
|
+
if (sum_minus_1 > 0) {
|
117
|
+
if (U != 0) {
|
118
|
+
p->U_pi = ((U - 1) / sum_minus_1) * M_start[0] +
|
119
|
+
(V / sum_minus_1) * M_start[1];
|
120
|
+
} else {
|
121
|
+
p->U_pi = 0.0;
|
122
|
+
}
|
123
|
+
|
124
|
+
if (V != 0) {
|
125
|
+
p->V_pi = (U / sum_minus_1) * M_start[2] +
|
126
|
+
((V - 1) / sum_minus_1) * M_start[3];
|
127
|
+
} else {
|
128
|
+
p->V_pi = 0.0;
|
129
|
+
}
|
130
|
+
|
131
|
+
} else {
|
132
|
+
p->U_pi = 0.0;
|
133
|
+
p->V_pi = 0.0;
|
134
|
+
}
|
135
|
+
|
136
|
+
p->pi_death_rates[0] = fabs(U * p->U_pi);
|
137
|
+
p->pi_death_rates[1] = fabs(V * p->V_pi);
|
138
|
+
|
139
|
+
p->pi_death_rates[2] = P_kappa_start[0] * U * (sum_minus_1 + 1.0);
|
140
|
+
p->pi_death_rates[3] = P_kappa_start[1] * V * (sum_minus_1 + 1.0);
|
141
|
+
|
142
|
+
p->sum_pi_death_rates = 0.0;
|
143
|
+
for (size_t i = 0; i < 4; i++) {
|
144
|
+
p->sum_pi_death_rates += p->pi_death_rates[i];
|
145
|
+
}
|
146
|
+
}
|
147
|
+
|
148
|
+
|
149
|
+
static inline void update_mig_one(patch_t* restrict p, const double* restrict P_start, uint8_t nb_loc) {
|
150
|
+
// update mig rate for one direction
|
151
|
+
// P_start: start index of p's patch variables, i.e., ij * 6
|
152
|
+
// nb_loc: location of neighbor, up, down, left, right
|
153
|
+
|
154
|
+
double mu1_U = P_start[0] * (double)p->U;
|
155
|
+
double mu2_V = P_start[1] * (double)p->V;
|
156
|
+
double* p_U_weight = p->U_weight;
|
157
|
+
double* p_V_weight = p->V_weight;
|
158
|
+
|
159
|
+
patch_t* nbi = p->nb[nb_loc];
|
160
|
+
p->sum_U_weight -= p_U_weight[nb_loc];
|
161
|
+
p->sum_V_weight -= p_V_weight[nb_loc];
|
162
|
+
|
163
|
+
switch(nb_loc) {
|
164
|
+
case MIG_UP:
|
165
|
+
p_U_weight[MIG_UP] = 1.0 + exp(P_start[2] * nbi->U_pi);
|
166
|
+
p_V_weight[MIG_UP] = 1.0 + exp(P_start[3] * nbi->V_pi);
|
167
|
+
break;
|
168
|
+
case MIG_DOWN:
|
169
|
+
p_U_weight[MIG_DOWN] = 1.0 + exp(P_start[2] * nbi->U_pi);
|
170
|
+
p_V_weight[MIG_DOWN] = 1.0 + exp(P_start[3] * nbi->V_pi);
|
171
|
+
break;
|
172
|
+
case MIG_LEFT:
|
173
|
+
p_U_weight[MIG_LEFT] = 1.0 + exp(P_start[2] * nbi->U_pi);
|
174
|
+
p_V_weight[MIG_LEFT] = 1.0 + exp(P_start[3] * nbi->V_pi);
|
175
|
+
break;
|
176
|
+
default:
|
177
|
+
p_U_weight[MIG_RIGHT] = 1.0 + exp(P_start[2] * nbi->U_pi);
|
178
|
+
p_V_weight[MIG_RIGHT] = 1.0 + exp(P_start[3] * nbi->V_pi);
|
179
|
+
break;
|
180
|
+
}
|
181
|
+
p->sum_U_weight += p_U_weight[nb_loc];
|
182
|
+
p->sum_V_weight += p_V_weight[nb_loc];
|
183
|
+
|
184
|
+
double mu1_U_divide_sum = mu1_U / p->sum_U_weight;
|
185
|
+
double mu2_V_divide_sum = mu2_V / p->sum_V_weight;
|
186
|
+
|
187
|
+
for (size_t i = 0; i < 4; i++) {
|
188
|
+
p->mig_rates[i] = mu1_U_divide_sum * p_U_weight[i];
|
189
|
+
p->mig_rates[i + 4] = mu2_V_divide_sum * p_V_weight[i];
|
190
|
+
}
|
191
|
+
|
192
|
+
}
|
193
|
+
|
194
|
+
|
195
|
+
|
196
|
+
static inline void update_mig_all(patch_t* restrict p, const double* restrict P_start) {
|
197
|
+
// update migration rate for all directions
|
198
|
+
double mu1_U = P_start[0] * (double)p->U;
|
199
|
+
double mu2_V = P_start[1] * (double)p->V;
|
200
|
+
|
201
|
+
double* p_U_weight = p->U_weight;
|
202
|
+
double* p_V_weight = p->V_weight;
|
203
|
+
|
204
|
+
p->sum_U_weight = 0.0;
|
205
|
+
p->sum_V_weight = 0.0;
|
206
|
+
|
207
|
+
double w1 = P_start[2];
|
208
|
+
double w2 = P_start[3];
|
209
|
+
|
210
|
+
for (uint8_t i = 0; i < 4; i++) {
|
211
|
+
patch_t* nbi = p->nb[i];
|
212
|
+
|
213
|
+
if (nbi) {
|
214
|
+
// not NULL
|
215
|
+
p_U_weight[i] = 1.0 + exp(w1 * nbi->U_pi);
|
216
|
+
p_V_weight[i] = 1.0 + exp(w2 * nbi->V_pi);
|
217
|
+
|
218
|
+
p->sum_U_weight += p_U_weight[i];
|
219
|
+
p->sum_V_weight += p_V_weight[i];
|
220
|
+
}
|
221
|
+
}
|
222
|
+
|
223
|
+
double mu1_U_divide_sum = mu1_U / p->sum_U_weight;
|
224
|
+
double mu2_V_divide_sum = mu2_V / p->sum_V_weight;
|
225
|
+
|
226
|
+
for (uint8_t i = 0; i < 4; i++) {
|
227
|
+
p->mig_rates[i] = mu1_U_divide_sum * p_U_weight[i];
|
228
|
+
p->mig_rates[i + 4] = mu2_V_divide_sum * p_V_weight[i];
|
229
|
+
}
|
230
|
+
|
231
|
+
p->sum_mig_rates = mu1_U + mu2_V;
|
232
|
+
}
|
233
|
+
|
234
|
+
|
235
|
+
|
236
|
+
static inline size_t find_event(const patch_t* restrict p, double expected_sum) {
|
237
|
+
size_t event = 0;
|
238
|
+
double current_sum;
|
239
|
+
|
240
|
+
//if (expected_sum > (p->sum_pi_death_rates + p->sum_mig_rates)) {
|
241
|
+
// fprintf(stderr, "Bug: patch rate not enough in find_event.\n");
|
242
|
+
//}
|
243
|
+
|
244
|
+
if (expected_sum < p->sum_pi_death_rates) {
|
245
|
+
// First 4 events (payoff and death)
|
246
|
+
current_sum = 0.0;
|
247
|
+
while (current_sum < expected_sum) {
|
248
|
+
current_sum += p->pi_death_rates[event];
|
249
|
+
event++;
|
250
|
+
}
|
251
|
+
event--; // step back to correct event index
|
252
|
+
} else {
|
253
|
+
// Last 8 events (migration)2
|
254
|
+
current_sum = p->sum_pi_death_rates;
|
255
|
+
while (current_sum < expected_sum) {
|
256
|
+
current_sum += p->mig_rates[event];
|
257
|
+
event++;
|
258
|
+
}
|
259
|
+
event += 3; // -1 and then +4
|
260
|
+
}
|
261
|
+
|
262
|
+
return event;
|
263
|
+
}
|
264
|
+
|
265
|
+
|
266
|
+
static inline void change_popu(patch_t* restrict p, uint8_t s) {
|
267
|
+
switch (s) {
|
268
|
+
case 0:
|
269
|
+
// Migration IN for U
|
270
|
+
p->U += 1;
|
271
|
+
return;
|
272
|
+
case 1:
|
273
|
+
// Migration OUT / death due to carrying capacity for U
|
274
|
+
p->U -= (p->U > 0);
|
275
|
+
return;
|
276
|
+
case 2:
|
277
|
+
// Natural birth/death for U due to payoff
|
278
|
+
if (p->U_pi > 0.0) {
|
279
|
+
p->U += 1;
|
280
|
+
} else if (p->U > 0) {
|
281
|
+
p->U -= 1;
|
282
|
+
}
|
283
|
+
return;
|
284
|
+
case 3:
|
285
|
+
// Migration IN for V
|
286
|
+
p->V += 1;
|
287
|
+
return;
|
288
|
+
case 4:
|
289
|
+
// Migration OUT / death due to carrying capacity for V
|
290
|
+
p->V -= (p->V > 0);
|
291
|
+
return;
|
292
|
+
default:
|
293
|
+
// Natural birth/death for V due to payoff
|
294
|
+
if (p->V_pi > 0.0) {
|
295
|
+
p->V += 1;
|
296
|
+
} else if (p->V > 0) {
|
297
|
+
p->V -= 1;
|
298
|
+
}
|
299
|
+
return;
|
300
|
+
//default:
|
301
|
+
// fprintf(stderr, "Bug: invalid event number in change_popu: %hhu\n", s);
|
302
|
+
// return;
|
303
|
+
}
|
304
|
+
}
|
305
|
+
|
306
|
+
|
307
|
+
/**
|
308
|
+
* Main Simulation Functions
|
309
|
+
*/
|
310
|
+
|
311
|
+
static inline void find_patch(patch_picked_t* restrict picked, double expected_sum, const double* restrict patch_rates, const double* restrict sum_rates_by_row, double sum_rates, size_t N, size_t M) {
|
312
|
+
double current_sum = 0;
|
313
|
+
size_t row = 0;
|
314
|
+
size_t col = 0;
|
315
|
+
|
316
|
+
// Find row
|
317
|
+
if (expected_sum < sum_rates * 0.5) {
|
318
|
+
current_sum = 0.0;
|
319
|
+
row = 0;
|
320
|
+
while (current_sum < expected_sum) {
|
321
|
+
current_sum += sum_rates_by_row[row];
|
322
|
+
row++;
|
323
|
+
}
|
324
|
+
row--;
|
325
|
+
current_sum -= sum_rates_by_row[row];
|
326
|
+
} else {
|
327
|
+
current_sum = sum_rates;
|
328
|
+
row = N - 1;
|
329
|
+
while (current_sum > expected_sum) {
|
330
|
+
current_sum -= sum_rates_by_row[row];
|
331
|
+
row--;
|
332
|
+
}
|
333
|
+
row++;
|
334
|
+
}
|
335
|
+
|
336
|
+
size_t row_M = row * M;
|
337
|
+
|
338
|
+
// Find col in that row
|
339
|
+
if ((expected_sum - current_sum) < sum_rates_by_row[row] * 0.5) {
|
340
|
+
col = 0;
|
341
|
+
while (current_sum < expected_sum) {
|
342
|
+
current_sum += patch_rates[row_M + col];
|
343
|
+
col++;
|
344
|
+
}
|
345
|
+
col--;
|
346
|
+
current_sum -= patch_rates[row_M + col];
|
347
|
+
} else {
|
348
|
+
current_sum += sum_rates_by_row[row];
|
349
|
+
col = M - 1;
|
350
|
+
while (current_sum > expected_sum) {
|
351
|
+
current_sum -= patch_rates[row_M + col];
|
352
|
+
col--;
|
353
|
+
}
|
354
|
+
col++;
|
355
|
+
}
|
356
|
+
|
357
|
+
picked->i = row;
|
358
|
+
picked->j = col;
|
359
|
+
picked->current_sum = current_sum;
|
360
|
+
}
|
361
|
+
|
362
|
+
|
363
|
+
|
364
|
+
static inline void make_signal_zero_flux(size_t i, size_t j, uint8_t e, signal_t* restrict signal) {
|
365
|
+
// this is always the case for the first one
|
366
|
+
signal->i1 = i;
|
367
|
+
signal->j1 = j;
|
368
|
+
|
369
|
+
switch (e) {
|
370
|
+
case 0:
|
371
|
+
signal->e1 = 2;
|
372
|
+
signal->only_first = true;
|
373
|
+
return;
|
374
|
+
case 1:
|
375
|
+
signal->e1 = 5;
|
376
|
+
signal->only_first = true;
|
377
|
+
return;
|
378
|
+
case 2:
|
379
|
+
signal->e1 = 1;
|
380
|
+
signal->only_first = true;
|
381
|
+
return;
|
382
|
+
case 3:
|
383
|
+
signal->e1 = 4;
|
384
|
+
signal->only_first = true;
|
385
|
+
return;
|
386
|
+
case 4:
|
387
|
+
signal->e1 = 1;
|
388
|
+
signal->i2 = i - 1;
|
389
|
+
signal->j2 = j;
|
390
|
+
signal->e2 = 0;
|
391
|
+
signal->only_first = false;
|
392
|
+
return;
|
393
|
+
case 5:
|
394
|
+
signal->e1 = 1;
|
395
|
+
signal->i2 = i + 1;
|
396
|
+
signal->j2 = j;
|
397
|
+
signal->e2 = 0;
|
398
|
+
signal->only_first = false;
|
399
|
+
return;
|
400
|
+
case 6:
|
401
|
+
signal->e1 = 1;
|
402
|
+
signal->i2 = i;
|
403
|
+
signal->j2 = j - 1;
|
404
|
+
signal->e2 = 0;
|
405
|
+
signal->only_first = false;
|
406
|
+
return;
|
407
|
+
case 7:
|
408
|
+
signal->e1 = 1;
|
409
|
+
signal->i2 = i;
|
410
|
+
signal->j2 = j + 1;
|
411
|
+
signal->e2 = 0;
|
412
|
+
signal->only_first = false;
|
413
|
+
return;
|
414
|
+
case 8:
|
415
|
+
signal->e1 = 4;
|
416
|
+
signal->i2 = i - 1;
|
417
|
+
signal->j2 = j;
|
418
|
+
signal->e2 = 3;
|
419
|
+
signal->only_first = false;
|
420
|
+
return;
|
421
|
+
case 9:
|
422
|
+
signal->e1 = 4;
|
423
|
+
signal->i2 = i + 1;
|
424
|
+
signal->j2 = j;
|
425
|
+
signal->e2 = 3;
|
426
|
+
signal->only_first = false;
|
427
|
+
return;
|
428
|
+
case 10:
|
429
|
+
signal->e1 = 4;
|
430
|
+
signal->i2 = i;
|
431
|
+
signal->j2 = j - 1;
|
432
|
+
signal->e2 = 3;
|
433
|
+
signal->only_first = false;
|
434
|
+
return;
|
435
|
+
default:
|
436
|
+
signal->e1 = 4;
|
437
|
+
signal->i2 = i;
|
438
|
+
signal->j2 = j + 1;
|
439
|
+
signal->e2 = 3;
|
440
|
+
signal->only_first = false;
|
441
|
+
return;
|
442
|
+
//default:
|
443
|
+
// fprintf(stderr, "Bug: invalid case in make_signal_zf, i, j, e: %zu, %zu, %hhu\n", i, j, e);
|
444
|
+
// return;
|
445
|
+
}
|
446
|
+
}
|
447
|
+
|
448
|
+
|
449
|
+
|
450
|
+
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) {
|
451
|
+
// this is always the case for the first one
|
452
|
+
signal->i1 = i;
|
453
|
+
signal->j1 = j;
|
454
|
+
|
455
|
+
switch (e) {
|
456
|
+
case 0:
|
457
|
+
signal->e1 = 2;
|
458
|
+
signal->only_first = true;
|
459
|
+
return;
|
460
|
+
case 1:
|
461
|
+
signal->e1 = 5;
|
462
|
+
signal->only_first = true;
|
463
|
+
return;
|
464
|
+
case 2:
|
465
|
+
signal->e1 = 1;
|
466
|
+
signal->only_first = true;
|
467
|
+
return;
|
468
|
+
case 3:
|
469
|
+
signal->e1 = 4;
|
470
|
+
signal->only_first = true;
|
471
|
+
return;
|
472
|
+
case 4:
|
473
|
+
signal->e1 = 1;
|
474
|
+
signal->i2 = i != 0 ? i - 1 : N - 1;
|
475
|
+
signal->j2 = j;
|
476
|
+
signal->e2 = 0;
|
477
|
+
signal->only_first = false;
|
478
|
+
return;
|
479
|
+
case 5:
|
480
|
+
signal->e1 = 1;
|
481
|
+
signal->i2 = i != N - 1 ? i + 1 : 0;
|
482
|
+
signal->j2 = j;
|
483
|
+
signal->e2 = 0;
|
484
|
+
signal->only_first = false;
|
485
|
+
return;
|
486
|
+
case 6:
|
487
|
+
signal->e1 = 1;
|
488
|
+
signal->i2 = i;
|
489
|
+
signal->j2 = j != 0 ? j - 1 : M - 1;
|
490
|
+
signal->e2 = 0;
|
491
|
+
signal->only_first = false;
|
492
|
+
return;
|
493
|
+
case 7:
|
494
|
+
signal->e1 = 1;
|
495
|
+
signal->i2 = i;
|
496
|
+
signal->j2 = j != M - 1 ? j + 1 : 0;
|
497
|
+
signal->e2 = 0;
|
498
|
+
signal->only_first = false;
|
499
|
+
return;
|
500
|
+
case 8:
|
501
|
+
signal->e1 = 4;
|
502
|
+
signal->i2 = i != 0 ? i - 1 : N - 1;
|
503
|
+
signal->j2 = j;
|
504
|
+
signal->e2 = 3;
|
505
|
+
signal->only_first = false;
|
506
|
+
return;
|
507
|
+
case 9:
|
508
|
+
signal->e1 = 4;
|
509
|
+
signal->i2 = i != N - 1 ? i + 1 : 0;
|
510
|
+
signal->j2 = j;
|
511
|
+
signal->e2 = 3;
|
512
|
+
signal->only_first = false;
|
513
|
+
return;
|
514
|
+
case 10:
|
515
|
+
signal->e1 = 4;
|
516
|
+
signal->i2 = i;
|
517
|
+
signal->j2 = j != 0 ? j - 1 : M - 1;
|
518
|
+
signal->e2 = 3;
|
519
|
+
signal->only_first = false;
|
520
|
+
return;
|
521
|
+
default:
|
522
|
+
signal->e1 = 4;
|
523
|
+
signal->i2 = i;
|
524
|
+
signal->j2 = j != M - 1 ? j + 1 : 0;
|
525
|
+
signal->e2 = 3;
|
526
|
+
signal->only_first = false;
|
527
|
+
return;
|
528
|
+
//default:
|
529
|
+
// fprintf(stderr, "Bug: invalid case in make_signal_pr, i, j, e: %zu, %zu, %hhu\n", i, j, e);
|
530
|
+
// return;
|
531
|
+
}
|
532
|
+
}
|
533
|
+
|
534
|
+
|
535
|
+
static inline bool nb_need_change(size_t nb_idx, size_t sij1, size_t sij2) {
|
536
|
+
// a nb doesn't need change only if two patches are updated
|
537
|
+
|
538
|
+
// or, can try this 1-line version
|
539
|
+
// return (nb_idx != sij1) && (nb_idx != sij2);
|
540
|
+
if ((nb_idx == sij1) || (nb_idx == sij2)) {
|
541
|
+
return false;
|
542
|
+
}
|
543
|
+
return true; // need to change
|
544
|
+
}
|
545
|
+
|
546
|
+
|
547
|
+
#endif
|
piegy/__init__.py
CHANGED
piegy/__version__.py
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
__version__ = '2.1.
|
1
|
+
__version__ = '2.1.9'
|
2
2
|
|
3
3
|
'''
|
4
4
|
version history:
|
@@ -28,4 +28,6 @@ version history:
|
|
28
28
|
2.0.4: minor debuggings.
|
29
29
|
2.0.5: fix error in random number generator.
|
30
30
|
2.1.0: redo random number generator. Update package upload so that more compatible across platforms.
|
31
|
+
2.1.1: fix import bug for the C core.
|
32
|
+
2.1.2 ~ 2.1.9: updating & fixing wheel.
|
31
33
|
'''
|
piegy/build_info.py
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
"""
|
2
|
+
Contains build info, whether it's local built, or a pre-compiled wheel.
|
3
|
+
Auto-generated at compile time.
|
4
|
+
"""
|
5
|
+
|
6
|
+
build_info = {
|
7
|
+
"version": "2.1.9",
|
8
|
+
"built from": "local machine",
|
9
|
+
"build date": "2025-06-28 09:00:03",
|
10
|
+
"python version": "3.8.10",
|
11
|
+
"platform": "win32"
|
12
|
+
}
|
piegy/find_C.py
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
'''
|
2
|
+
This module is used to find the C core
|
3
|
+
'''
|
4
|
+
|
5
|
+
import os
|
6
|
+
|
7
|
+
|
8
|
+
def find_C():
|
9
|
+
C_core_path = os.path.join(os.path.dirname(__file__), 'C_core')
|
10
|
+
C_list = os.listdir(C_core_path)
|
11
|
+
for file in C_list:
|
12
|
+
if file[-3:] == '.so':
|
13
|
+
return C_core_path + '/' + file
|
14
|
+
if file[-4:] == '.pyd':
|
15
|
+
return C_core_path + '/' + file
|
16
|
+
|
17
|
+
raise FileNotFoundError('C computation core not found. You can either compile manully or use the Python core instead. Please see docs.')
|
piegy/simulation.py
CHANGED
@@ -12,6 +12,7 @@ Class & Functions:
|
|
12
12
|
- check_overflow_func: check whether an overflow might happen in simulation. This is usually done automatically when init-ing a model.
|
13
13
|
'''
|
14
14
|
|
15
|
+
from . import find_C
|
15
16
|
|
16
17
|
import numpy as np
|
17
18
|
import os
|
@@ -21,14 +22,15 @@ import numpy as np
|
|
21
22
|
from numpy.ctypeslib import ndpointer
|
22
23
|
|
23
24
|
|
24
|
-
# path to the C shared libary
|
25
|
-
C_LIB_PATH = os.path.join(os.path.dirname(__file__), 'C_core', 'piegyc.so')
|
26
|
-
|
27
25
|
# check whether overflow / too large values might be encountered
|
28
26
|
# these values are considered as exponents in exp()
|
29
27
|
EXP_OVERFLOW_BOUND = 709 # where exp(x) reaches overflow bound
|
30
28
|
EXP_TOO_LARGE_BOUND = 88 # where exp(x) reaches 1e20
|
31
29
|
|
30
|
+
# read the C core into LIB
|
31
|
+
# initialized upon first run
|
32
|
+
LIB = None
|
33
|
+
|
32
34
|
|
33
35
|
'''
|
34
36
|
The C core
|
@@ -69,23 +71,28 @@ class model_c(ctypes.Structure):
|
|
69
71
|
ptr = getattr(self, name)
|
70
72
|
return np.ctypeslib.as_array(ptr, shape=(self.arr_size,))
|
71
73
|
|
72
|
-
lib = ctypes.CDLL(C_LIB_PATH, winmode = 0)
|
73
|
-
lib.mod_init.argtypes = [
|
74
|
-
ctypes.POINTER(model_c), c_size_t, c_size_t,
|
75
|
-
c_double, c_double, c_size_t, c_bool,
|
76
|
-
ndpointer(dtype=np.uint32, flags="C_CONTIGUOUS"),
|
77
|
-
ndpointer(dtype=np.float64, flags="C_CONTIGUOUS"),
|
78
|
-
ndpointer(dtype=np.float64, flags="C_CONTIGUOUS"),
|
79
|
-
c_int32, c_int32
|
80
|
-
]
|
81
|
-
lib.mod_init.restype = c_bool
|
82
74
|
|
83
|
-
|
84
|
-
|
75
|
+
def read_lib():
|
76
|
+
global LIB
|
77
|
+
if LIB != None:
|
78
|
+
return
|
79
|
+
|
80
|
+
LIB = ctypes.CDLL(find_C.find_C(), winmode = 0)
|
81
|
+
LIB.mod_init.argtypes = [
|
82
|
+
ctypes.POINTER(model_c), c_size_t, c_size_t,
|
83
|
+
c_double, c_double, c_size_t, c_bool,
|
84
|
+
ndpointer(dtype=np.uint32, flags="C_CONTIGUOUS"),
|
85
|
+
ndpointer(dtype=np.float64, flags="C_CONTIGUOUS"),
|
86
|
+
ndpointer(dtype=np.float64, flags="C_CONTIGUOUS"),
|
87
|
+
c_int32, c_int32
|
88
|
+
]
|
89
|
+
LIB.mod_init.restype = c_bool
|
85
90
|
|
86
|
-
|
87
|
-
|
91
|
+
LIB.mod_free_py.argtypes = [ctypes.POINTER(model_c)]
|
92
|
+
LIB.mod_free_py.restype = None
|
88
93
|
|
94
|
+
LIB.run.argtypes = [ctypes.POINTER(model_c), ctypes.POINTER(c_char), c_size_t]
|
95
|
+
LIB.run.restype = None
|
89
96
|
|
90
97
|
|
91
98
|
|
@@ -396,6 +403,8 @@ def run(mod, message = ""):
|
|
396
403
|
C-cored simulation
|
397
404
|
'''
|
398
405
|
|
406
|
+
read_lib()
|
407
|
+
|
399
408
|
if not mod.data_empty:
|
400
409
|
raise ValueError('mod has non-empty data.')
|
401
410
|
|
@@ -408,20 +417,20 @@ def run(mod, message = ""):
|
|
408
417
|
P = np.ascontiguousarray(mod.P.flatten(), dtype = np.float64)
|
409
418
|
|
410
419
|
mod_c = model_c()
|
411
|
-
success =
|
420
|
+
success = LIB.mod_init(ctypes.byref(mod_c),
|
412
421
|
mod.N, mod.M, mod.maxtime, mod.record_itv, mod.sim_time, mod.boundary,
|
413
422
|
I, X, P, mod.print_pct, mod.seed)
|
414
423
|
if not success:
|
415
424
|
raise RuntimeError('mod_init failed')
|
416
425
|
|
417
|
-
|
426
|
+
LIB.run(ctypes.byref(mod_c), msg_buffer, msg_len)
|
418
427
|
|
419
428
|
mod.set_data(False, mod.max_record, 1, mod_c.get_array('U1d').reshape(mod.N, mod.M, mod.max_record),
|
420
429
|
mod_c.get_array('V1d').reshape(mod.N, mod.M, mod.max_record),
|
421
430
|
mod_c.get_array('Upi_1d').reshape(mod.N, mod.M, mod.max_record),
|
422
431
|
mod_c.get_array('Vpi_1d').reshape(mod.N, mod.M, mod.max_record))
|
423
432
|
|
424
|
-
|
433
|
+
LIB.mod_free_py(ctypes.byref(mod_c))
|
425
434
|
del mod_c
|
426
435
|
|
427
436
|
|