source: experiments/frams/foraminifera/data/scripts/forams_benthic.expdef @ 401

Last change on this file since 401 was 401, checked in by Maciej Komosinski, 9 years ago

Extended Foraminifera simulation - physical collisions; visible haplo/diplo generations; growing; and much more

File size: 14.4 KB
Line 
1expdef:
2name:Benthic foraminifera reproduction
3info:~
4Genes and parameter values which control reproduction are stored in user1 and user2 fields.
5
6user1:
7genes which are not encoded in ff genotype:
8Vamin - Minimum stored energy necessary for reproduction
9amin - minimal age for reproduction
10
11user2:
12Physiological parameters of foraminifera:
13Va - amount of the stored energy
14gen - generation: 0 haploid, 1 diploid
15~
16code:~
17
18/*
19changes 2015-06-24:
20- xxx.get(...) changed to xxx[...]
21- xxx.set(...,...) changed to xxx[...]=...
22- function placeRandomlyNotColliding(cr) explicitly called when adding a new creature, and removed collision checking from onCreaturesBorn() which is also called when "growing" (since "growing" is implemented as creating a new creature in place of the old one, so onCreaturesBorn() is also called)
23- use creature's center (not the bbox corner) when growing
24- added "S" receptor to visualize the difference between diplo and haplo generations
25- signal.value is a MechPart (a reference) so it does not have to be updated after changing the object location
26*/
27
28global foodenergywaiting;
29global reprocounter;
30global delta_change;
31
32@include "forams_repro.inc"
33
34// -------------------------------- experiment begin --------------------------------
35
36function onExpDefLoad()
37{
38
39        // define genotype and creature groups
40        GenePools.clear();
41        Populations.clear();
42        GenePools[0].name = "Unused";
43
44        SignalView.mode = 1;
45
46        var pop = Populations[0];
47        pop.name = "Creatures";
48        pop.en_assim = 0;
49        pop.nnsim = 1;
50        pop.enableperf = 1;
51        pop.death = 1;
52        pop.energy = 1;
53        pop.selfmask = 0x10001;
54        pop.othermask = 0x20001;
55        //pop.selfmask = 0x20002; pop.othermask = 0x10002;
56        pop.perfperiod = 25;
57
58        pop = Populations.addGroup("Food");
59        pop.nnsim = 0;
60        pop.enableperf = 0;
61        pop.death = 1;
62        pop.energy = 1;
63        pop.selfmask = 0x20002;
64        pop.othermask = 0x10000;
65
66
67        var size_h = ExpParams.haplo_rad * ExpParams.delta_rate + ExpParams.haplo_rad;
68        var size_d = ExpParams.diplo_rad * ExpParams.delta_rate + ExpParams.diplo_rad;
69        ExpParams.gend = "//0\np:sh=1,sx=" + ExpParams.diplo_rad + ",sy=" + ExpParams.diplo_rad + ",sz=" + ExpParams.diplo_rad + ", rz=3.14159265358979";
70        ExpParams.genh = "//0\np:sh=1,sx=" + size_h + ",sy=" + size_h + ",sz=" + size_h + ", rz=3.14159265358979";
71        ExpParams.e_meta = 0.1;
72        ExpParams.feedrate = 0.5;
73        ExpParams.feede0 = 100;
74        ExpParams.feedtrans = 3;
75        ExpParams.creath = -0.99; //just above the bottom
76        ExpParams.foodgen = "//0\np:sh=2,sx=0.1,sy=0.1,sz=0.1\nn:d=T,p=0";
77        ExpParams.autorestart = 0;
78        ExpParams.psize = 10;
79        ExpParams.logging = 0;
80
81        //number of offspring
82        ExpParams.ofnumh = 40;
83        ExpParams.ofnumd = 25;
84        //minial volume for reproduction
85        ExpParams.v_min_d = 300;
86        ExpParams.v_min_h = 300;
87        //radius of the chamber
88        ExpParams.haplo_rad = 1.2;
89        ExpParams.diplo_rad = 0.6;
90        //minimal age for reproduction
91        ExpParams.age_min_d = 100;
92        ExpParams.age_min_h = 100;
93        //crossover probability
94        ExpParams.crossprob = 0.4;
95        //mutation probability
96        ExpParams.mutationprob = 0.2;
97        ExpParams.repro_time = 200;
98        ExpParams.repro_thr = 1;
99
100        //size change rate
101        ExpParams.delta_rate = 0.1;
102        //grwoth speed in time steps
103        ExpParams.growth_step = 50;
104
105        ExpState.totaltestedcr = 0;
106        ExpState.food = "";
107        foodenergywaiting = ExpParams.feede0;
108        reprocounter = 0;
109
110        ExpParams.wsize = 50;
111        World.wrldwat = 50;
112        World.wrldsiz = ExpParams.wsize;
113        World.wrldbnd = 1;
114
115        delta_change = 0.5;
116}
117
118@include "standard_placement.inc"
119
120function onExpInit()
121{
122        Populations[0].clear();
123        Populations[1].clear();
124
125        for (var i = 0; i < ExpParams.psize; i++)
126        {
127                var cr = Populations[0].add(ExpParams.genh);
128                cr.name = "Initial creature" + i;
129                placeCreatureRandomly(cr, 0, 0);
130                cr.energ0 = ExpParams.v_min_h - ExpParams.repro_thr;
131                cr.energy = cr.energ0;
132                cr.user1 = {"vamin" : ExpParams.v_min_h, "amin": ExpParams.age_min_h, "delta_h" : ExpParams.haplo_rad * ExpParams.delta_rate, "delta_d" : ExpParams.diplo_rad * ExpParams.delta_rate};
133                cr.user2 = {"Va" : ExpParams.v_min_h - ExpParams.repro_thr, "gen" : 0, "growth_step" : ExpParams.growth_step, "rsize" : ExpParams.haplo_rad, "vinit" : ExpParams.v_min_h - ExpParams.repro_thr};
134        }
135        ExpState.totaltestedcr = 0;
136        foodenergywaiting = ExpParams.feede0;
137}
138
139function onExpLoad()
140{
141        for (var pop in Populations)
142                pop.clear();
143
144        Loader.addClass(sim_params.*);
145        Loader.setBreakLabel(Loader.BeforeUnknown, "onExpLoad_Unknown");
146        Loader.run();
147
148        Simulator.print("Loaded " + Populations[0].size + " creatures and " + Populations[1].size + " food objects");
149}
150
151function onExpLoad_Unknown()
152{
153        if (Loader.objectName == "org") // saved by the old expdef
154        {
155                var g = Genotype.newFromString("");
156                Loader.currentObject = g;
157                Interface.makeFrom(g).setAllDefault();
158                Loader.loadObject();
159                var cr = Populations[0].add(g);
160                if (cr != null)
161                {
162                        //cr.rotate(0,0,Math.rnd01*Math.twopi);
163                        if ((typeof(g.user1) == "Vector") && (g.user1.size >= 3))
164                        {
165                                // [x,y,energy]
166                                cr.move(g.user1[0] - cr.center_x, g.user1[1] - cr.center_y, 0);
167                                cr.energy = g.user1[2];
168                        }
169                        else
170                        {
171                                cr.move(Math.rnd01 * World.wrldsiz - cr.center_x, Math.rnd01 * World.wrldsiz - cr.center_y, 0);
172                        }
173                }
174        }
175        else if (Loader.objectName == "Creature")
176        {
177                Loader.currentObject = CreatureSnapshot.new();
178                Loader.loadObject();
179                Populations[0].add(Loader.currentObject);
180        }
181}
182
183function onExpSave()
184{
185        File.writeComment("saved by '%s.expdef'" % Simulator.expdef);
186
187        var tmpvec = [], i;
188
189        for(var cr in Populations[1])
190                tmpvec.add([cr.center_x, cr.center_y, cr.energy]);
191
192        ExpState.food = tmpvec;
193        File.writeObject(sim_params.*);
194        ExpState.food = null; //vectors are only created for saving and then discarded
195
196        for (var cr in Populations[0])
197                File.writeObject(cr);
198}
199
200// -------------------------------- experiment end --------------------------------
201
202// -------------------------------- creature begin --------------------------------
203
204function onCreaturesBorn(cr)
205{
206        cr.idleen = ExpParams.e_meta;
207}
208
209function placeRandomlyNotColliding(cr)
210{
211        var retry = 100; //try 100 times
212        while (retry--)
213        {
214                placeCreatureRandomly(cr, 0, 0);
215                if (!cr.boundingBoxCollisions(0))
216                        return cr;
217        }
218
219        Populations[0].delete(cr);
220}
221
222function readyToRepro(cr)
223{
224        cr.signals.add("repro");
225        cr.signals[0].power = 1;
226
227}
228
229function onCreaturesStep(cr)
230{
231        cr.moveAbs(cr.pos_x, cr.pos_y, 0); //adjustment in z axis
232        var p = cr.getMechPart(0);
233        var n = cr.signals.receiveSet("food", ExpParams.food_range);
234
235        //if signals are received find the source of the nearest
236        if (n.size > 0)
237        {
238
239                var i;
240                var mp;
241                var distvec = XYZ.new(0, 0, 0);
242                var dist;
243                var mindist = 100000000000;
244                var mindistvec = null;
245
246                for (i = 0; i < n.size; i++)
247                {
248                        mp = n[i].value;
249                        distvec.set(mp.pos);
250                        distvec.sub(p.pos);
251                        dist = distvec.length;
252                        if (dist < mindist)
253                        {
254                                mindist = dist;
255                                mindistvec = distvec.clone();
256                        }
257                }
258
259                mindistvec.normalize();
260                mindistvec.scale(-0.08);
261                cr.localDrive = mindistvec;
262        }
263
264        else
265        {
266                cr.localDrive = (0.1 * Math.rnd01, 0.1 * Math.rnd01, 0);
267        }
268
269        //energy costs depend on size
270        if (cr.energy > 100)
271        {
272                // cr.energy_m = cr.user2["Va"]/cr.user2["vinit"];
273        }
274
275        if (cr.lifespan >= ExpParams.max_age)
276        {
277                Populations[0].kill(cr);
278        }
279
280        //foram growth
281        else if (cr.lifespan == cr.user2["growth_step"])
282        {
283                var pos = [cr.center_x, cr.center_y, cr.center_z];
284                var energy = cr.energy;
285                var cr2 = null;
286                if (cr.user2["gen"] == 0)
287                {
288                        var new_r = ExpParams.haplo_rad * Math.min(Math.max(cr.user2["Va"] / cr.user2["vinit"] * 0.5, 1), 2.5);
289                        cr.user2["rsize"] = new_r;
290                        cr2 = Populations[0].add("//0\np:sh=1,sx=" + cr.user2["rsize"] + ",sy=" + cr.user2["rsize"] + ",sz=" + cr.user2["rsize"] + ", rz=3.14159265358979");
291                        cr2.user1 = {"vamin" : cr.user1["vamin"], "amin": cr.user1["amin"], "delta_h" : cr.user1["delta_h"], "delta_d" : cr.user1["delta_d"]};
292                }
293                else if (cr.user2["gen"] == 1)
294                {
295                        var new_r = ExpParams.diplo_rad * Math.min(Math.max(cr.user2["Va"] / cr.user2["vinit"] * 0.5, 1), 2.5);
296                        cr.user2["rsize"] = new_r;
297
298                        var geno = "//0\np:sh=1,sx=" + cr.user2["rsize"] + ",sy=" + cr.user2["rsize"] + ",sz=" + cr.user2["rsize"] + ", rz=3.14159265358979";
299                        geno += "\nn:p=0,d=\"S\""; //TODO is this the only difference with haploid code? TODO why initial genotypes are not used as defined in ExpParams?
300                        //TODO maybe it would be nice if they rotated so the "S" would show where they are going (direction/intention)
301                        cr2 = Populations[0].add(geno);
302
303
304                        cr2.user1 = [ {"vamin" : cr.user1[0]["vamin"], "amin": cr.user1[0]["amin"], "delta_h" : cr.user1[0].get("delta_h"), "delta_d" : cr.user1[0]["delta_d"]  }, {"vamin" : cr.user1[1]["vamin"], "amin": cr.user1[1]["amin"], "delta_h" : cr.user1[1]["delta_h"], "delta_d" : cr.user1[1]["delta_d"]  }];
305                }
306                cr2.energy = energy;
307                cr2.user2 = {"Va" : cr.user2["Va"], "gen" : cr.user2["gen"], "growth_step" : cr.user2["growth_step"], "rsize" : cr.user2["rsize"], "vinit": cr.user2["vinit"]};
308                cr2.moveAbs(cr.center_x - cr2.size_x / 2, cr.center_y - cr2.size_y / 2, cr.pos_z);
309
310                Populations[0].delete(cr);
311        }
312        else
313        {
314                var properSize = 0;
315
316                if (cr.user2["gen"] == 0)
317                {
318                        properSize = cr.user2["Va"] >= cr.user1["vamin"];
319                }
320                else
321                {
322                        properSize = cr.user2["Va"] >= cr.user1[0]["vamin"];
323                }
324
325                //if creature has proper age and cytoplasm amount
326                if ( properSize )
327                {
328                        //reproduce with probability repro_prob
329                        if (Math.rnd01 <= ExpParams.repro_prob)
330                        {
331                                readyToRepro(cr);
332                        }
333                }
334                if ( properSize && (cr.signals.receive("repro") > 0))
335                {
336                        readyToRepro(cr);
337                }
338        }
339}
340
341function onCreaturesDied(cr)
342{
343        //fossilization
344        var geno = GenePools[0].add(cr.genotype);
345        geno.user1 = cr.user1;
346        geno.user2 = cr.user2;
347        Simulator.print("\"" + cr.name + "\" died...");
348        ExpState.totaltestedcr++;
349}
350
351// -------------------------------- creature end --------------------------------
352
353// -------------------------------- food begin --------------------------------
354
355function onFoodStep(cr)
356{
357        cr.moveAbs(cr.pos_x % ExpParams.wsize, cr.pos_y % ExpParams.wsize, 0.5);
358}
359
360function addfood()
361{
362        var cr = Populations[1].add(ExpParams.foodgen);
363
364        cr.name = "Food";
365        cr.idleen = 0;
366        cr.energ0 = ExpParams.feede0;
367        cr.energy = cr.energ0;
368        cr.signals.add("food");
369
370        cr.signals[0].value = cr.getMechPart(0);
371
372        var retry = 100; //try 100 times
373        while (retry--)
374        {
375                placeCreatureRandomly(cr, 0, 0);
376                if (!cr.boundingBoxCollisions(0))
377                        return cr;
378        }
379
380        return cr;
381}
382
383function onFoodCollision()
384{
385        if (Collision.Creature2.user2 != null)
386        {
387                var e = Collision.Part2.ing * ExpParams.feedtrans;
388                //Simulator.print("transferring "+e+" from "+Collision.Creature1.name+" to "+Collision.Creature2.name+" ("+Collision.Creature2.energy+")");
389                Collision.Creature1.energy_m = Collision.Creature1.energy_m + e;
390                Collision.Creature2.energy_p = Collision.Creature2.energy_p + e;
391                var ener = float(Collision.Creature2.user2["Va"]);
392                var sum = float(float(ener) + float(e));
393                Collision.Creature2.user2["Va"] = float(sum);
394        }
395}
396
397// -------------------------------- food end --------------------------------
398
399
400function log(tolog, fname)
401{
402        var f = File.appendDirect(fname, "forams data");
403        f.writeString("" + Simulator.stepNumber);
404        for (var  i = 0; i < tolog.size; i++)
405        {
406                f.writeString(";" + tolog[i]);
407        }
408        f.writeString("\n");
409        f.close();
410}
411
412
413
414
415@include "standard_events.inc"
416
417~
418
419prop:
420id:max_age
421name:Maximal age
422type:d 100 1000 500
423
424prop:
425id:wsize
426name:World size
427type:d 10 1000 20
428
429prop:
430id:haplo_rad
431name:Haploid radius
432type:f 0.1 3 1.2
433
434prop:
435id:growth_step
436name:Growth step
437type:d 50 10000 1000
438
439prop:
440id:delta_rate
441name:Delta rate
442type:f 0.0001 0.1 0.001
443
444prop:
445id:diplo_rad
446name:Diploid radius
447type:f 0.1 3 0.6
448
449prop:
450id:foodPop
451name:Food size
452type:d 1 1000 10
453
454prop:
455id:age_min
456name:Minimal age for reproduction
457type:d 100 10000 200
458
459prop:
460id:age_min_h
461name:Min reproduction age of haploid forams
462type:d 100 10000 300
463group:Foraminifera
464
465prop:
466id:age_min_d
467name:Min reproduction age of diploid forams
468type:d 100 10000 200
469group:Foraminifera
470
471prop:
472id:v_min_h
473name:Min reproduction energy of haploid forams
474type:f 10 10000 300
475group:Foraminifera
476
477prop:
478id:v_min_d
479name:Min reproduction energy of diploid forams
480type:f 10 10000 150
481group:Foraminifera
482
483prop:
484id:repro_thr
485name:Threshold for reproduction
486type:d 1 1000 1
487
488prop:
489id:food_range
490name:Range of food smell
491type:d 0 10000 10000
492
493prop:
494id:repro_time
495name:Time before reproduction
496type:d 0 1000
497
498prop:
499id:psize
500name:Initial population size
501type:d 1 1000 100
502
503prop:
504id:logging
505name:Log statistics to file
506type:d 0 1 0
507
508prop:
509id:ofnumh
510name:Number of offspring from haploid forams
511type:d
512group:Foraminifera
513
514prop:
515id:ofnumd
516name:Number of offspring from diploid forams
517type:d
518group:Foraminifera
519
520prop:
521id:repro_prob
522name:Probability of reproduction
523type:f 0 1 0.9
524
525prop:
526id:crossprob
527name:Crossover probability
528type:f 0 1 0
529
530prop:
531id:mutationprob
532name:Mutation probability
533type:f 0 1 0
534
535prop:
536id:genh
537name:Initial genotype of haploid forams
538type:s 1
539group:Foraminifera
540
541prop:
542id:gend
543name:Initial genotype of diploid forams
544type:s 1
545group:Foraminifera
546
547prop:
548id:creath
549name:Creation height
550type:f -1 50
551help:~
552Vertical position (above the surface) where new creatures are revived.
553Negative values are only used in the water area:
554  0   = at the surface
555-0.5 = half depth
556-1   = just above the bottom~
557
558prop:
559id:e_meta
560name:Idle metabolism
561type:f 0 1
562group:Energy
563help:Each stick consumes this amount of energy in one time step
564
565prop:
566id:feedrate
567name:Feeding rate
568type:f 0 100
569group:Energy
570help:How fast energy is created in the world
571
572prop:
573id:feede0
574name:Food's energy
575group:Energy
576type:f 0 1000
577
578prop:
579id:feedtrans
580name:Ingestion multiplier
581group:Energy
582type:f 0 100
583
584prop:
585id:foodgen
586name:Food's genotype
587group:Energy
588type:s 1
589
590prop:
591id:autorestart
592name:Restart after extinction
593help:Restart automatically this experiment after the last creature has died?
594type:d 0 1
595
596state:
597id:notes
598name:Notes
599type:s 1
600help:~
601You can write anything here
602(it will be saved to the experiment file)~
603
604state:
605id:totaltestedcr
606name:Evaluated creatures
607help:Total number of the creatures evaluated in the experiment
608type:d
609flags:16
610
611state:
612id:food
613name:Food locations
614help:vector of vectors [x,y,energy]
615type:x
616flags:32
617
Note: See TracBrowser for help on using the repository browser.