1
+ // MIMICS JAVA CLASS: AGENT-BASED MODEL AND REACTION-DIFFUSION MODEL
2
+ package MIMICS ;
3
+
4
+ // IMPORT HAL PACKAGES
5
+ import HAL .GridsAndAgents .*;
6
+ import HAL .Rand ;
7
+ import HAL .Tools .FileIO ;
8
+ import HAL .Util ;
9
+ import static HAL .Util .*;
10
+
11
+ // IMPORT JAVA PACKAGES
12
+ import java .io .BufferedWriter ;
13
+ import java .io .FileWriter ;
14
+ import java .io .IOException ;
15
+ import java .util .ArrayList ;
16
+ import java .util .Random ;
17
+
18
+ // CREATE CELL3D AGENT CLASS
19
+ class Cell3D extends SphericalAgent3D <Cell3D , MIMICS >
20
+ {
21
+ Random r = new Random ();
22
+ Rand rn = new Rand ();
23
+ // DEFINE AGENT ATTRIBUTES
24
+ double mass ; // BIOMASS
25
+ double forceSum ;// AGENT SUM OF FORCES
26
+ double angle ; // AGENT ANGLE
27
+ int index ; // AGENT INDEX
28
+ double growth_rate ; // AGENT GROWTH RATE
29
+ int metabolic_state ; // AGENT METABOLIC STATE
30
+ double t_switch_0 ; // AGENT TRACKING TIME TO SWITCH TO METABOLIC STATE 0
31
+ double t_switch_1 ; // AGENT TRACKING TIME TO SWITCH TO METABOLIC STATE 1
32
+
33
+ // METHODS TO INITIALIZE AN AGENT
34
+ public void Init (double mass ,double angle , int state , int index , double t_switch_0 , double t_switch_1 ) {
35
+ // INITIALIZE VALUES OF AGENT ATTRIBUTES
36
+ this .mass = mass ;
37
+ this .angle = angle ;
38
+ this .radius = G .RADIUS ;
39
+ this .index = index ;
40
+ this .metabolic_state = state ;
41
+ this .t_switch_0 = t_switch_0 / 2 ;
42
+ this .t_switch_1 = t_switch_1 / 2 ;
43
+ }
44
+
45
+ // METHOD TO CALCULATE SHOVING FORCES BETWEEN AGENTS
46
+ double ForceCalc (double overlap , Cell3D other ){
47
+ if (overlap <0 ) {
48
+ return 0 ; // IF NO AGENT OVERLAP, RETURN 0
49
+ }
50
+ return G .FORCE_SCALER *overlap ; // SCALE OVERLAP (HOOKE'S LAW)
51
+ }
52
+
53
+ // METHOD TO PERFORM SHOVING FORCES BETWEEN AGENTS
54
+ public void CalcMove (){
55
+ forceSum =SumForces (G .RADIUS ,this ::ForceCalc );
56
+ }
57
+
58
+ // METHOD TO MOVE AGENTS
59
+ public void MoveDiv (){
60
+ ForceMove ();
61
+ ApplyFriction (this .G .FRICTION );
62
+ }
63
+
64
+ // METHOD TO SIMULATE AGENT BIOMASS DIVISION
65
+ public int Biomass_Divide (int pop , double initial_biomass , double max_biomass ) {
66
+ int birth_counter =0 ; // VARIABLE TO KEEP TRACK OF NUMBER OF CELL DIVISIONS TO UPDATE AGENT INDEX
67
+
68
+ // PERFORM BIOMASS DIVISION FOR AGENTS WITH HIGH BIOMASS
69
+ if (this .mass > max_biomass ) {
70
+ Random r = new Random ();
71
+ double new_mass = initial_biomass + (max_biomass - initial_biomass )/2 * r .nextDouble (); // CALCULATE DAUGHTER AGENT BIOMASS
72
+
73
+ this .mass = this .mass - new_mass ; // UPDATE MOTHER AGENT BIOMASS
74
+ double angle2 = this .angle + -10 + (int ) (Math .random () * ((10 - (-10 )) + 1 )); //CALCULATE DAUGHTER AGENT ANGLE
75
+
76
+ // CALCULATE DAUGHTER AGENT X,Y,Z COORDINATES
77
+ double dx = 1 + (1 - 0.5 ) * r .nextDouble ();
78
+ double dy = 1 + (1 - 0.5 ) * r .nextDouble ();
79
+ dx = dx * Math .cos (angle );
80
+ dy = dy * Math .sin (angle ); ;
81
+ double dz = 0 ;
82
+ double neg_pos_x = Math .random ();
83
+ double neg_pos_y = Math .random ();
84
+ if (neg_pos_x > 0.5 ){
85
+ dx = -dx ;
86
+ }
87
+ if (neg_pos_y > 0.5 ){
88
+ dy = -dy ;
89
+ }
90
+ if (Math .random ()>0.5 & this .Zpt ()<20 ) {
91
+ Random randomno = new Random ();
92
+ dz = randomno .nextGaussian ()*0.1 +0.6 ;
93
+ if (dz < 0 ){
94
+ dz = 0.4 ;
95
+ }
96
+ }
97
+
98
+ // GENERATE DAUGHTER AGENT
99
+ G .NewAgentPTSafe (this .Xsq ()+dx ,this .Ysq ()+dy ,this .Zsq ()+dz ).Init (new_mass ,angle2 , this .metabolic_state , pop , this .t_switch_0 , this .t_switch_1 );
100
+ birth_counter = birth_counter + 1 ; // UPDATE BIRTH COUNTER
101
+ }
102
+ return birth_counter ;
103
+ }
104
+
105
+ }
106
+
107
+ // MIMICS MODEL CLASS
108
+ public class MIMICS extends AgentGrid3D <Cell3D > {
109
+ public MIMICS (int xdim , int ydim , int zdim ) {
110
+ super (xdim , ydim , zdim , Cell3D .class );
111
+ } // CREATE MIMICS CLASS
112
+ Rand rn = new Rand ();
113
+
114
+ // CREATE ARRAY LISTS FOR AGENT NEIGHBORS
115
+ ArrayList <Cell3D > neighborList = new ArrayList <>();
116
+ ArrayList <Cell3D > neighborList2 = new ArrayList <>();
117
+ ArrayList <double []> neighborInfo = new ArrayList <>();
118
+ AgentList <Cell3D > cells = new AgentList <>();
119
+ int [] vnHood2d = MooreHood (false ); // AGENT 2D NEIGHBORHOOD
120
+
121
+ // INITIALIZE MAXIMUM CELL INDEX
122
+ int max_cell_index = 0 ;
123
+
124
+ // INITIALIZE ARRAYS CONTAINING METABOLITE PDE GRIDS
125
+ ArrayList <PDEGrid3D > carbon_metabolites = new ArrayList <PDEGrid3D >(); // CARBON METABOLITE PDE GRIDS
126
+ ArrayList <PDEGrid3D > gas_metabolites = new ArrayList <PDEGrid3D >(); // GAS METABOLITE PDE GRIDS
127
+
128
+ // DEFINE AGENT PARAMETERS USED FOR FORCE CALCULATIONS
129
+ double RADIUS ; // AGENT RADIUS
130
+ double FORCE_SCALER ; // FORCE SCALAR
131
+ double FRICTION ; // FRICTION SCALAR
132
+
133
+ // METHOD TO SAVE AGENT INFORMATION AT A DESIRED SIMULATION TIME POINT
134
+ public void Save_Cell_Info (int time , int rep ,int pop , String file_name ) throws IOException {
135
+ double [][] output = new double [pop ][11 ]; // OUTPUT MATRIX: [ROWS: EACH AGENT, COLUMNS: AGENT ATTRIBUTES]
136
+ int c = 0 ; // INITIALIZE OUTPUT MATRIX ROW INDEX
137
+ for (Cell3D cell : this ) { // ITERATE OVER EACH AGENT
138
+ double x = cell .Xpt (); double y = cell .Ypt (); double z = cell .Zpt (); // AGENT X,Y,Z COORDINATES
139
+ // ASSIGN VALUES TO OUTPUT MATRIX
140
+ output [c ][0 ] = time ;
141
+ output [c ][1 ] = cell .index ;
142
+ output [c ][2 ] = x ;
143
+ output [c ][3 ] = y ;
144
+ output [c ][4 ] = z ;
145
+ output [c ][5 ] = cell .metabolic_state ;
146
+ output [c ][6 ] = cell .mass ;
147
+ output [c ][7 ] = cell .growth_rate ;
148
+ output [c ][8 ] = gas_metabolites .get (0 ).Get (x , y , z );
149
+ output [c ][9 ] = carbon_metabolites .get (0 ).Get (x , y , z );
150
+ output [c ][10 ] = rep ;
151
+ c = c +1 ;
152
+ }
153
+
154
+ if (time == 0 ) { // INITIALIZE A NEW CSV OUTPUT FILE IF TIME STEP = 0
155
+ StringBuilder sb = new StringBuilder (); // INITIALIZE STRING BUILDER
156
+
157
+ // ASSIGN COLUMN TITLES (correspond to the order of attributes in the output matrix above)
158
+ sb .append ("time" ); sb .append ("," );
159
+ sb .append ("cell index" ); sb .append ("," );
160
+ sb .append ("xcor" ); sb .append ("," );
161
+ sb .append ("ycor" ); sb .append ("," );
162
+ sb .append ("zcor" ); sb .append ("," );
163
+ sb .append ("metabolic_state" ); sb .append ("," );
164
+ sb .append ("biomass" ); sb .append ("," );
165
+ sb .append ("growth_rate" ); sb .append ("," );
166
+ sb .append ("oxygen" ); sb .append ("," );
167
+ sb .append ("glucose" ); sb .append ("," );
168
+ sb .append ("job_num" ); sb .append ('\n' );
169
+
170
+ // ADD AGENT OUTPUTS TO STRING BUILDER FOR CSV FILE
171
+ for (int j = 0 ; j < pop ; j ++) { // ITERATE OVER EACH AGENT
172
+ for (int i = 0 ; i < 11 ; i ++) { // ITERATE OVER EACH OUTPUT METRIC
173
+ sb .append (output [j ][i ]); sb .append ("," ); }
174
+ sb .append ('\n' ); }
175
+
176
+ // WRITE OUTPUT TO NEW CSV
177
+ BufferedWriter br = new BufferedWriter (new FileWriter (file_name ));
178
+ br .write (sb .toString ());
179
+ br .close ();
180
+ }
181
+
182
+ if (time != 0 ) { // APPEND OUTPUT MATRIX TO EXISTING CSV IF TIME IS NOT ZERO
183
+ StringBuilder sb = new StringBuilder ();
184
+ for (int j = 0 ; j < pop ; j ++) { // ITERATE OVER EACH AGENT
185
+ for (int i = 0 ; i < 11 ; i ++) { // ITERATE OVER EACH OUTPUT METRIC
186
+ sb .append (output [j ][i ]); sb .append ("," ); }
187
+ sb .append ('\n' );
188
+ }
189
+ // APPEND OUTPUT TO EXISTING CSV
190
+ BufferedWriter br = new BufferedWriter (new FileWriter (file_name ,true ));
191
+ br .write (sb .toString ());
192
+ br .close ();
193
+ }
194
+ }
195
+
196
+ // METHOD TO SAVE METABOLITE CONCENTRATION INFORMATION
197
+ public void Save_Met_Info (int time , int rep , String file_name ) throws IOException {
198
+ double [][] output = new double [xDim * yDim * zDim ][7 ]; // METABOLITE ARRAY: [rows: 3D metabolite grid location, columns: output metrics]
199
+ int c = 0 ; // INITIALIZE OUTPUT MATRIX ROW INDEX
200
+ // ITERATE OVER EACH PATCH LOCATION IN METABOLITE GRID
201
+ for (int x = 0 ; x < xDim ; x ++) {
202
+ for (int z = 0 ; z < zDim ; z ++) {
203
+ for (int y = 0 ; y < yDim ; y ++) {
204
+ output [c ][0 ] = x ;
205
+ output [c ][1 ] = y ;
206
+ output [c ][2 ] = z ;
207
+ output [c ][3 ] = gas_metabolites .get (0 ).Get (x , y , z );
208
+ output [c ][4 ] = carbon_metabolites .get (0 ).Get (x , y , z );
209
+ output [c ][5 ] = time ;
210
+ output [c ][6 ] = rep ;
211
+ c = c + 1 ;
212
+ }
213
+ }
214
+ }
215
+
216
+ if (time == 0 ) { // INITIALIZE NEW CSV OUTPUT FILE IF TIME STEP = 0
217
+ BufferedWriter br = new BufferedWriter (new FileWriter (file_name ));
218
+ StringBuilder sb = new StringBuilder ();
219
+ // ASSIGN OUTPUT TITLES (correspond to the order of metrics in output matrix above)
220
+ sb .append ("xcor" );
221
+ sb .append ("," );
222
+ sb .append ("ycor" );
223
+ sb .append ("," );
224
+ sb .append ("zcor" );
225
+ sb .append ("," );
226
+ sb .append ("oxygen" );
227
+ sb .append ("," );
228
+ sb .append ("glucose" );
229
+ sb .append ("," );
230
+ sb .append ("time" );
231
+ sb .append ("," );
232
+ sb .append ("job_num" ); sb .append ('\n' );
233
+
234
+ // SAVE OUTPUT MATRIX TO STRING BUILDER AND WRITE TO NEW CSV FILE
235
+ for (int j = 0 ; j < xDim * yDim * zDim ; j ++) { // ITERATE OVER EACH LOCATION IN 3D METABOLITE GRID
236
+ for (int i = 0 ; i < 7 ; i ++) { // ITERATE OVER EACH METRIC
237
+ sb .append (output [j ][i ]);
238
+ sb .append ("," );
239
+ }
240
+ sb .append ('\n' );
241
+ }
242
+ br .write (sb .toString ());
243
+ br .close ();
244
+ }
245
+
246
+ if (time != 0 ) { // IF TIME IS NOT ZERO, APPEND TO EXISTING CSV FILE
247
+ BufferedWriter br = new BufferedWriter (new FileWriter (file_name , true ));
248
+ StringBuilder sb = new StringBuilder ();
249
+
250
+ for (int j = 0 ; j < xDim * yDim * zDim ; j ++) { // ITERATE OVER EACH LOCATION IN 3D METABOLITE GRID
251
+ for (int i = 0 ; i < 7 ; i ++) {
252
+ sb .append (output [j ][i ]);
253
+ sb .append ("," );
254
+ }
255
+ sb .append ('\n' );
256
+ }
257
+ br .write (sb .toString ());
258
+ br .close ();
259
+ }
260
+ }
261
+
262
+ // METHOD TO INITIALIZE METABOLITE CONCENTRATIONS IN ALL LOCATIONS IN METABOLITE PDE GRID
263
+ public void Initialize_Metabolites (int num_met_gas , double [] initial_gas_concentrations , int num_met_carbon ,double [] initial_carbon_concentrations ) {
264
+ // INITIALIZE GAS METABOLITE CONCENTRATIONS
265
+ for (int m = 0 ; m < num_met_gas ; m ++) {
266
+ gas_metabolites .get (m ).SetAll (initial_gas_concentrations [m ]); // UNITS: mM
267
+ gas_metabolites .get (m ).Update ();
268
+ }
269
+ // INITIALIZE CARBON METABOLITE CONCENTRATIONS
270
+ for (int m = 0 ; m < num_met_carbon ; m ++) {
271
+ carbon_metabolites .get (m ).SetAll (initial_carbon_concentrations [m ]); // UNITS: mM
272
+ carbon_metabolites .get (m ).Update ();
273
+ }
274
+ }
275
+
276
+ // METHOD TO DIFFUSE GASES
277
+ public void Gas_Diffuse (int num_met_gas ,double [] initial_gas_concentration , double [] D_gas , int num_gas_step ) {
278
+ for (int i = 0 ; i < num_gas_step ; i ++) { // PERFORM GAS DIFFUSION FOR A DISCRETE NUMBER OF TIME STEPS
279
+ // SET AREAS WITHOUT AGENTS TO A CONSTANT CONCENTRATION
280
+ for (int x = 0 ; x < xDim ; x ++) {
281
+ for (int z = 0 ; z < zDim ; z ++) {
282
+ for (int y = 0 ; y < yDim ; y ++) {
283
+ if (GetAgent (x , y , z ) == null ) {
284
+ int [] vnHood3d = Util .MooreHood3D (false );
285
+ int ct = MapEmptyHood (vnHood3d , x , y , z );
286
+ int ct_max = MapHood (vnHood3d , x , y , z );
287
+ if (ct == ct_max ) {
288
+ for (int m = 0 ; m < num_met_gas ; m ++) {
289
+ gas_metabolites .get (m ).Set (x , y , z , initial_gas_concentration [m ]);
290
+ }
291
+ }
292
+ }
293
+ }
294
+ }
295
+ }
296
+ for (int m = 0 ; m < num_met_gas ; m ++) {
297
+ gas_metabolites .get (m ).Update (); // UPDATE METABOLITE CONCENTRATIONS
298
+ gas_metabolites .get (m ).DiffusionADI (D_gas [m ]); // DIFFUSE METABOLITE CONCENTRATIONS
299
+ gas_metabolites .get (m ).Update (); // UPDATE METABOLITE CONCENTRATIONS
300
+ }
301
+ }
302
+ }
303
+
304
+
305
+ // METHOD TO DIFFUSE CARBON SUBSTRATES
306
+ public void Carbon_Diffuse (int num_met_carbon ,double [] initial_carbon_concentration ,double [] D_carbon , int num_carbon_step ) {
307
+ for (int i = 0 ; i < num_carbon_step ; i ++) { // PERFORM CARBON DIFFUSION FOR A DISCRETE NUMBER OF TIME STEPS
308
+ // SET AREAS WITHOUT AGENTS TO A CONSTANT CONCENTRATION
309
+ for (int x = 0 ; x < xDim ; x ++) {
310
+ for (int z = 0 ; z < zDim ; z ++) {
311
+ for (int y = 0 ; y < yDim ; y ++) {
312
+ if (GetAgent (x , y , z ) == null ) {
313
+ int [] vnHood3d = Util .MooreHood3D (false );
314
+ int ct = MapEmptyHood (vnHood3d , x , y , z );
315
+ int ct_max = MapHood (vnHood3d , x , y , z );
316
+ if (ct == ct_max ) {
317
+ for (int m = 0 ; m < num_met_carbon ; m ++) {
318
+ carbon_metabolites .get (m ).Set (x , y , z , initial_carbon_concentration [m ]);
319
+ }
320
+ }
321
+ }
322
+ }
323
+ }
324
+ }
325
+ for (int m = 0 ; m < num_met_carbon ; m ++) {
326
+ carbon_metabolites .get (m ).Update (); // UPDATE METABOLITE CONCENTRATIONS
327
+ carbon_metabolites .get (m ).DiffusionADI (D_carbon [m ]); // DIFFUSE METABOLITE CONCENTRATIONS
328
+ carbon_metabolites .get (m ).Update (); // UPDATE METABOLITE CONCENTRATIONS
329
+ }
330
+ }
331
+ }
332
+
333
+ // METHOD TO PERFORM AGENT METHODS
334
+ public void StepCells (double initial_biomass ,double max_biomass ,int dead_state ) {
335
+ CleanAgents (); // CLEAN REMOVED AGENTS IF NECESSARY
336
+ // ITERATE OVER EACH AGENT
337
+ for (Cell3D cell : this ) {
338
+ if (cell .metabolic_state != dead_state ) { // IF THE CELL IS NOT DEAD
339
+
340
+ // PERFORM AGENT BIOMASS DIVISION
341
+ int birth_counter = cell .Biomass_Divide (max_cell_index ,initial_biomass ,max_biomass );
342
+
343
+ // RESET MAXIMUM CELL INDEX (USED TO ASSIGN NEW CELL INDEX TO DAUGHTER CELLS) IF DIVISION EVENT OCCURED
344
+ if (birth_counter > 0 ) {
345
+ max_cell_index = max_cell_index + 1 ;
346
+ }
347
+
348
+ // PERFORM CELL MECHANICS
349
+ for (int i = 0 ; i < 5 ; i ++) {
350
+ cell .CalcMove ();
351
+ cell .MoveDiv ();
352
+ }
353
+ }
354
+ }
355
+ CleanAgents (); // CLEAN REMOVED AGENTS IF NECESSARY
356
+ }
357
+
358
+ // METHOD TO RANDOMLY INITIALIZE AGENTS
359
+ public void Initialize_Random (int b0 , double initial_biomass , double max_biomass ) {
360
+ max_cell_index = b0 ; // SET MAXIMUM CELL INDEX
361
+ for (int j = 0 ; j <= max_cell_index -1 ; j ++) { // j DEFINES THE AGENT INDEX
362
+ double x = rn .Double (xDim ); // X-COORDINATE
363
+ double y = rn .Double (yDim ); // Y-COORDINATE
364
+ Random r = new Random ();
365
+ double old_mass = initial_biomass + (max_biomass - initial_biomass ) * r .nextDouble (); // SET AGENT BIOMASS
366
+ int angle = rn .Int (360 ); // INITIALIZE CELL ANGLE
367
+ int metabolic_state = 0 ; // INITIALIZE METABOLIC MODEL STATE
368
+ NewAgentPT (x , y , 0 ).Init (old_mass ,angle , metabolic_state , j , 0 , 0 );
369
+ }
370
+ }
371
+
372
+ // METHOD TO CALL MAIN METHOD
373
+ static int count = 0 ;
374
+ public static void mainCaller () throws IOException , NoSuchFieldException , IllegalAccessException {
375
+ count ++;
376
+ while (count == 1 ) {
377
+ main (null );
378
+ }
379
+ }
380
+
381
+ public static void main (String [] args ) throws IOException , NoSuchFieldException , IllegalAccessException {
382
+ mainCaller (); // MAIN METHOD USED EXTERNALLY IN MIMICS GATEWAY CLASS
383
+ }
384
+ }
0 commit comments