source: experiments/frams/foraminifera/data/scripts/foraminifera.expdef @ 714

Last change on this file since 714 was 638, checked in by sz, 8 years ago

script updated (moveAbs, size_, pos_, center_)

File size: 32.5 KB
Line 
1expdef:
2name:Reproduction of benthic foraminifera
3info:~
4Basic information about this simulation:
5www.framsticks.com/foraminifera
6
7Technical information:
8Genes and parameter values which control reproduction are stored in data->genes and data->lifeparams fields.
9
10genes:
11genes which are not encoded in Ff genotype:
12min_repro_energy - Minimum energy necessary for reproduction
13hibernation - Defines foram behavior in the case of no nutrients
14
15lifeparams:
16Physiological parameters of foraminifera:
17max_energy_level - maximum energy level reached so far
18gen - generation: 0 haploid, 1 diploid
19species - species: 0 not hibernating 1 hibernating
20hibernated - 0/1 foram is/isn't hibernated
21reproduce - 0/1 foram isn't/is ready for reproduction
22~
23code:~
24
25global colors;
26global curColor;
27global max_chamber_volume;
28global movePerStep;
29global reprocounter;
30global changePeriod;
31global phase;
32global nutrientSqrCm;
33global species_genes;
34global max_chambers_def;
35global foram_uid; //introduced because each replacement of a creature (while growing) would generate a new Creature.uid
36global chamber_vis_denominator;
37global curRadius;
38global nutrient_num_counter;
39global wrldsizSquareMeters;
40
41@include "foraminifera.inc"
42
43// -------------------------------- experiment begin --------------------------------
44
45function onExpDefLoad()
46{
47        // define genotype and creature groups
48        GenePools.clear();
49        Populations.clear();
50        GenePools[0].name = "Unused";
51
52        var pop = Populations[0];
53        pop.name = "Forams";
54        pop.en_assim = 0;
55        pop.nnsim = 0;
56        pop.enableperf = 1;
57        pop.death = 1;
58        pop.energy = 1;
59        pop.selfmask = 0;
60        pop.othermask = 0;
61        //pop.selfmask = 0x20002; pop.othermask = 0x10002;
62        pop.perfperiod = 25;
63        pop.bodysim = 0;
64
65        pop = Populations.addGroup("Nutrients");
66        pop.nnsim = 0;
67        pop.enableperf = 0;
68        pop.death = 1;
69        pop.energy = 1;
70        pop.selfmask = 0;
71        pop.othermask = 0;
72        //pop.othermask = 0x10002;
73        pop.bodysim = 0;
74
75        pop = Populations.addGroup("ReticulopodiaNutrients");
76        pop.nnsim = 0;
77        pop.enableperf = 0;
78        pop.death = 0;
79        pop.energy = 0;
80        pop.selfmask = 0;
81        pop.othermask = 0;
82        pop.bodysim = 0;
83
84        //world
85        SignalView.mode = 1;
86        World.wrldwat = 200;
87        World.wrldsiz = micronsToFrams(100000);
88        wrldsizSquareMeters = Math.pow(framsToMicrons(World.wrldsiz)*0.000001,2);
89        World.wrldbnd = 1;
90
91        //ExpProperties.visualize = 1; //uncomment to visualize reticulopodia and indicate nutrients positions
92
93        //ExpProperties.logging = 1; //uncomment to enable logging simulation parameters to log files   
94        ExpProperties.logPref = "";
95
96        //morphology
97        ExpProperties.zone1_range = micronsToFrams(1000);
98        ExpProperties.zone2_range = micronsToFrams(3000);
99        ExpProperties.chamber_proculus_haplo = micronsToFrams(20);
100        ExpProperties.chamber_proculus_diplo = micronsToFrams(10);
101        colors = ["1.0,1.0,0.3","1.0,0.7,0.0"]; //yellow and orange
102        curColor = colors[0];
103        curRadius = ExpProperties.zone1_range;
104
105        //nutrients
106        ExpProperties.nutrientradius = micronsToFrams(10);
107        ExpProperties.energy_nut = 200 * energyFromVolume(ExpProperties.nutrientradius,1);
108        nutrientSqrCm = 10;
109        ExpProperties.nutrient_pop = Math.pow(framsToMicrons(World.wrldsiz)*0.0001,2)/nutrientSqrCm;
110
111        ExpState.totaltestedcr = 0;
112        ExpState.nutrient = "";
113
114        max_chambers_def = 35;
115        chamber_vis_denominator = 12;
116        //addSpecies({"min_repro_energies" : [4,6]});
117        //addSpecies({"min_repro_energies" : [4,8]});
118       
119        //Simulator.print(create_genotype(0.2, 30, "1.0,1.0,0.0", 0.6)); //sample call
120        //Simulator.print(create_genotype(0.1, 40, "1.0,0.5,0.0", 0.1)); //sample call
121}
122
123@include "standard_placement.inc"
124
125function onExpInit()
126{
127        species_genes = [];
128        foram_uid = 0;
129        movePerStep = getMovePerStep();
130
131        Populations[0].clear();
132        Populations[1].clear();
133        Populations[2].clear(); //reticulopodia and nutrients
134
135        if (ExpProperties.max_chamber_num_haplo == max_chambers_def && ExpProperties.max_chamber_num_diplo == max_chambers_def)
136        {
137                max_chamber_volume = [[30403.5869594578,52812.2546633948,79578.5148482541,113588.815134453,154620.677376218,205094.322220826,262572.712174265,326078.453295303,402342.518962956,498133.985678766,615066.864740109,759500.497626816,937064.025544282,1155915.25563075,1429139.14079748,1762487.92940157,2176286.62046069,2685795.63187845,3316190.12127043,4096436.04462706,5051343.25226193,6231980.1061213,7687880.79524734,9485307.02904958,11716968.9852569,14459866.4934433,17836388.9853663,22004935.7247348,27138607.2546045,33482425.1582986,41336775.1280297,50997910.7842793,62888631.7871037,77563060.9243464,95659468.591964]
138, [3430.07716920763,6159.93090353532,9322.94192815286,13462.9896597283,18399.8550832969,24558.9218126892,31468.8148639192,39189.4977865513,48404.4292075836,60185.8639086061,74490.6048472854,92117.8178412275,113852.779747083,140714.366929552,174450.937643841,215250.242147183,266323.295274072,328858.042352538,406552.379957238,503526.321155323,621060.781025019,767240.824049468,947210.683224091,1169506.19906112,1447211.61255879,1787155.29073739,2205627.64766244,2723413.2837305,3360233.53738709,4147771.02835393,5126445.06973928,6328060.3331703,7805693.278958,9631924.72156452,11884287.1596814]];
139        }
140
141        else
142        {
143                max_chamber_volume = [Vector.new(), Vector.new()];
144                var density = 100;
145                for (var ploid = 0; ploid < 2; ploid++)
146                {
147                        var rad = getPloidRadius(ploid);
148                        for (var cham_num = 0; cham_num < getProperty(ploid,"max_chamber_num"); cham_num++)
149                        {
150                                max_chamber_volume[ploid].add(volumeFromGeno(ploid, rad, cham_num+1, density));
151                        }                                 
152                }
153        }
154
155        if (species_genes.size == 0)
156        {
157                addSpecies({}); //default
158        }
159
160        for (var spec = 0; spec < species_genes.size; spec++)
161        {
162                for (var i = 0; i < ExpProperties.foramPop; i++)
163                {
164                        addInitialForam(spec, i);       
165                }
166        }
167        ExpState.totaltestedcr = 0;
168
169        reprocounter = 0;
170        nutrient_num_counter = 0;
171        changePeriod = 0;
172        phase = "low";
173}
174
175function onExpLoad()
176{
177        for (var pop in Populations)
178                pop.clear();
179
180        Loader.addClass(sim_params.*);
181        Loader.setBreakLabel(Loader.BeforeUnknown, "onExpLoad_Unknown");
182        Loader.run();
183
184        Simulator.print("Loaded " + Populations[0].size + " Forams and " + Populations[1].size + " nutrient objects");
185}
186
187function onExpLoad_Unknown()
188{
189        if (Loader.objectName == "org") // saved by the old expdef
190        {
191                var g = Genotype.newFromString("");
192                Loader.currentObject = g;
193                Interface.makeFrom(g).setAllDefault();
194                Loader.loadObject();
195                var cr = Populations[0].add(g);
196                if (cr != null)
197                {
198                        //cr.rotate(0,0,Math.rnd01*Math.twopi);
199                        if ((typeof(g.data->genes) == "Vector") && (g.data->genes.size >= 3))
200                        {
201                                // [x,y,energy]
202                                cr.move(g.data->genes[0] - cr.bboxCenter.x, g.data->genes[1] - cr.bboxCenter.y, 0);
203                                cr.energy = g.data->genes[2];
204                        }
205                        else
206                        {
207                                cr.move(Math.rnd01 * World.wrldsiz - cr.bboxCenter.x, Math.rnd01 * World.wrldsiz - cr.bboxCenter.y, 0);
208                        }
209                }
210        }
211        else if (Loader.objectName == "Creature")
212        {
213                Loader.currentObject = CreatureSnapshot.new();
214                Loader.loadObject();
215                Populations[0].add(Loader.currentObject);
216        }
217}
218
219function onExpSave()
220{
221        File.writeComment("saved by '%s.expdef'" % Simulator.expdef);
222
223        var tmpvec = [], i;
224
225        for(var cr in Populations[1])
226                tmpvec.add([cr.bboxCenter.x, cr.bboxCenter.y, cr.energy]);
227
228        ExpState.nutrient = tmpvec;
229        File.writeObject(sim_params.*);
230        ExpState.nutrient = null; //vectors are only created for saving and then discarded
231
232        for (var cr in Populations[0])
233                File.writeObject(cr);
234}
235
236// -------------------------------- experiment end --------------------------------
237
238function volumeFromGeno(morphotype, rad, chamber_num, density)
239{
240        var geno = create_genotype(rad, chamber_num, colors[morphotype], 1);
241        var m=Model.newFromString(geno);
242        var mg=ModelGeometry.forModel(m);
243        mg.geom_density=density;
244        var volumeInFrams = mg.volume();
245
246        return volumeInFrams/Math.pow(ExpProperties.scalingFactor,3);
247}
248
249function secToSimSteps(value_in_sec){
250        return value_in_sec/ExpProperties.secPerStep;
251}
252
253function volumeInMicrons(radiusInFrams)
254{
255        return 4.0/3.0*Math.pi*Math.pow(framsToMicrons(radiusInFrams),3);
256}
257
258function energyFromVolume(base, isRadiusInFrams)
259{
260        if (isRadiusInFrams == 1) //radius in frams
261        {
262                return ExpProperties.picoCarbonPerMikro*volumeInMicrons(base);
263        }
264        else //volume in microns
265        {
266                return ExpProperties.picoCarbonPerMikro * base;
267        }
268}
269
270function getMovePerStep()
271{
272        return micronsToFrams((ExpProperties.foramSpeedMmPerMin/60)*1000)*ExpProperties.secPerStep;
273}
274
275function micronsToFrams(micrometers)
276{
277        return micrometers*ExpProperties.scalingFactor;
278}
279
280function framsToMicrons(framsworldunits)
281{
282        return framsworldunits/ExpProperties.scalingFactor;
283}
284
285function getProperty(gen, prop_id)
286{
287        var ploid = "haplo";
288        if (gen == 1) ploid = "diplo";
289        return ExpProperties.[prop_id + "_" + ploid];
290}
291
292function getGene(cr, gen_id, gen_set)
293{
294        if (cr.data->lifeparams->gen == 0)
295                return cr.data->genes[gen_id];
296        else
297                return cr.data->genes[gen_set][gen_id];
298}
299
300function getPloidRadius(ploid)
301{
302        var radius = ExpProperties.chamber_proculus_haplo;
303                if (ploid == 1)
304                {
305                        radius = ExpProperties.chamber_proculus_diplo;
306                }
307        return radius;
308}
309
310function chamberNumFromEnergy(energy, ploid)
311{
312        var chamber_num = max_chamber_volume[ploid].size;
313        for (var i = 0; i < chamber_num; i++)
314        {
315                if (energy < energyFromVolume(max_chamber_volume[ploid][i],0))
316                {
317                        chamber_num = i+1;
318                        break;
319                }       
320        }                                 
321       
322        return chamber_num;
323}
324
325function createAndRotate(geno, rotate_min, rotate_max, pop_num)
326{
327        var cr = Populations[pop_num].add(geno);
328        cr.rotate(0,0,Math.rndUni(rotate_min, rotate_max));
329        return cr;     
330}
331
332//TODO unifiy addForam, foramGrow and createOffspring
333function addForam(species, iter, start_energy, ploid)
334{
335        var chambernum =  chamberNumFromEnergy(start_energy, ploid);
336        var radius = getPloidRadius(ploid);
337        var geno = create_genotype(radius, chambernum, colors[ploid], 1);
338        curColor = colors[ploid];
339        var cr = createAndRotate(geno, 0, 2*Math.pi, 0);
340        cr.name = "Initial creature" + species + "_" + iter;
341        placeRandomlyNotColliding(cr);
342        cr.energy = start_energy;
343        setGenotype({"opt" : "birth", "cr" : cr, "gen" : ploid, "species" : species, "energy0" : cr.energy, "genes" : species_genes[species], "parentsuids" : ["c0"]});
344        if (ploid == 1)
345        {
346                cr.data->genes = [cr.data->genes, cr.data->genes]; //TODO two different genes sets
347        }
348        moveReticulopodia(cr);
349}
350
351function addInitialForam(species, iter)
352{
353        var ploid = 0;
354        if (Math.rnd01 > 0.5)
355        {
356                ploid = 1;
357        }       
358        //add new foram with random energy bewtween starting energy and reproduction threshold
359        var repro_thr = species_genes[species]->min_repro_energies[ploid];
360        var start_energy = Math.rndUni(energyFromVolume(getPloidRadius(ploid),1),repro_thr-0.25*repro_thr);
361        addForam(species, iter, start_energy,ploid);
362}
363
364//new species can be added as a dictionary with parameter values that are different than default values
365function addSpecies(new_genes)
366{
367        species_genes.add({"min_repro_energies" : [ExpProperties.min_repro_energ_haplo,ExpProperties.min_repro_energ_diplo], "energies0" : [ExpProperties.energies0_haplo, ExpProperties.energies0_diplo], "hibernation" : 0, "morphotype" : 0});
368        for (var i = 0; i < new_genes.size; i++)
369        {
370                var key = new_genes.getKey(i);
371                species_genes[species_genes.size-1][key] = new_genes[key];
372        }
373}
374
375// -------------------------------- foram begin -----------------------------------
376
377function setForamMeta(cr)
378{
379        //percent of current energy
380        cr.idleen = (ExpProperties.e_meta * cr.energy)*ExpProperties.secPerStep;
381}
382
383function lastChamberNum(cr)
384{
385        return cr.numparts;
386}
387
388function getZoneRange(cr, zone_num)
389{
390        return ExpProperties.["zone"+zone_num+"_range"];
391}
392
393function addReticulopodia(cr, radius)
394{
395                if (reticulopodiaExists(cr))
396                {
397                        Populations[2].delete(cr.data->reticulopodiacreature);
398                }
399                var ret = Populations[2].add("//0\nm:Vstyle=reticulopodia\np:sh=1,sx=0.001,sy=0.001,sz=0.001\np:sh=3,sx=0.01,sy="+radius+",sz="+radius+",ry=1.57079633,vr="+curColor+"\nj:0, 1, sh=1");
400                cr.data->reticulopodiacreature = ret;
401                ret.getMechPart(0).orient.set(cr.getMechPart(0).orient);
402                ret.locationSetBboxLow(cr.bboxCenter.x-radius, cr.bboxCenter.y-radius, cr.bboxCenter.z-radius);
403}
404
405function onForamsBorn(cr)
406{
407        setForamMeta(cr);
408        if (ExpProperties.visualize == 1)
409        {
410                addReticulopodia(cr, curRadius);
411                moveReticulopodia(cr);
412        }
413}
414
415function placeRandomlyNotColliding(cr)
416{
417        var retry = 100; //try 100 times
418        while (retry--)
419        {
420                placeCreatureRandomly(cr, 0, 0);
421                if (!cr.boundingBoxCollisions(0))
422                {
423                        cr.locationSetBboxLow(cr.bboxLow.x, cr.bboxLow.y, -cr.getPart(cr.numparts-1).sx); //place slightly under the bottom surface ("z" value depends on the size of the last=largest chamber)
424                        return cr;
425                }
426        }
427
428        Populations[0].delete(cr);
429}
430
431function reticulopodiaExists(cr)
432{
433        var has_ret = 0;
434
435        if (cr.data->reticulopodiacreature != null)
436        {
437                if (Populations[2].findUID(cr.data->reticulopodiacreature.uid) != null)
438                {
439                        has_ret = 1;
440                }
441        }
442
443        return has_ret;
444}
445
446function visualization(cr)
447{
448        return reticulopodiaExists(cr);
449}
450
451function foramGrow(cr, chamber_num, lastchambergrowth)
452{
453        if ((chamber_num+1) <= max_chamber_volume[cr.data->lifeparams->gen].size)
454        {
455                curColor = colors[cr.data->lifeparams->gen];
456                var ploid = cr.data->lifeparams->gen;
457                var geno = create_genotype(getPloidRadius(ploid), chamber_num+1, colors[ploid], lastchambergrowth);
458                var cr2 = createAndRotate(geno, 0, 0, 0);
459
460                cr2.orient.set(cr.orient);
461                cr2.energy0 = cr.energy;
462                cr2.energy = cr2.energy0;
463
464                setGenotype({"cr" : cr2, "parent_genes" : cr.data->genes, "parent_lifeparams" : cr.data->lifeparams, "opt" : "growth", "energy0" : cr.energy0});
465                cr2.locationSetBboxLow(cr.bboxLow.x, cr.bboxLow.y,cr.bboxLow.z);
466                setForamMeta(cr2);
467
468                if (reticulopodiaExists(cr))
469                {
470                        Populations[2].delete(cr.data->reticulopodiacreature);
471                }
472                Populations[0].delete(cr);
473                return cr2;
474        }
475        return cr;
476}
477
478function visualizeChamberGrowth(cr, chamber_time)
479{
480        var total_time = secToSimSteps(ExpProperties.chamberGrowthSec);
481        var ret_unit = total_time/chamber_vis_denominator;
482        var chamber_unit = total_time-ret_unit;
483
484        if (chamber_time < ret_unit || chamber_time >= chamber_unit)
485        {
486                var new_rad = Math.min(Math.max((chamber_time%ret_unit)/ret_unit*getZoneRange(cr,1),0.01),getZoneRange(cr,1));
487
488                if(chamber_time < ret_unit)
489                {
490                        new_rad = getZoneRange(cr,1)-new_rad;
491                }
492
493                curColor = colors[cr.data->lifeparams->gen];
494                addReticulopodia(cr,new_rad);
495
496                if (chamber_time == 0)//checking for end of chamber growth process
497                {
498                        cr.data->lifeparams->chamber_growth = -1;       
499                }
500        }
501        else
502        {
503                var new_rad = 1 - Math.min(Math.max((chamber_time-ret_unit)/chamber_unit,0.01),1);
504                curRadius = cr.data->reticulopodiacreature.getPart(1).sy;
505                               
506                if (chamber_time == ret_unit)
507                {
508                        new_rad = 1;
509                }
510
511                var new_cr = foramGrow(cr, chamberNumFromEnergy(cr.data->lifeparams->max_energy_level, cr.data->lifeparams->gen)-1, new_rad);
512                curRadius = getZoneRange(new_cr,1);
513        }
514}
515
516function stepToNearest(cr)
517{
518        var p = XYZ.new(cr.bboxCenter.x, cr.bboxCenter.y, cr.bboxCenter.z);
519        var n = cr.signals.receiveSet("nutrient", getZoneRange(cr,2));
520
521        //if signals are received find the source of the nearest
522        if (n.size > 0)
523        {
524                var i;
525                var mp;
526                var distvec = XYZ.new(0, 0, 0);
527                var dist;
528                var mindist = 100000000000.0;
529                var mindistvec = null;
530                var eating = 0;
531
532                for (i = 0; i < n.size; i++)
533                {
534                        mp = XYZ.new(n[i].value.bboxCenter.x, n[i].value.bboxCenter.y, n[i].value.bboxCenter.z);
535                        distvec.set(mp);
536                        distvec.sub(p);
537                        dist = distvec.length;
538                        if (dist < getZoneRange(cr,1))
539                        {
540                                if (n[i].value != null)
541                                {
542                                        energyTransfer(cr, n[i].value);
543                                        eating = 1;
544                                }
545                        }
546                        else if (eating == 0 && cr.data->lifeparams->hibernated == 0 && dist < mindist)
547                        {
548                                mindist = dist;
549                                mindistvec = distvec.clone();
550                        }
551                }
552
553                if (!eating && cr.data->lifeparams->hibernated == 0)
554                {
555                        mindistvec.z = 0;
556                        mindistvec.normalize();
557                        mindistvec.scale(movePerStep);
558                        cr.drive = mindistvec;
559                        moveEnergyDec(cr);
560                }
561
562                return 1;
563        }
564       
565        else
566        {
567                return 0;
568        }
569}
570
571function moveEnergyDec(cr)
572{
573        if (cr.data->lifeparams->hibernated == 0)
574        {
575                //percent of maximal energy
576                cr.energy -= (ExpProperties.energy_move * cr.data->lifeparams->max_energy_level)*ExpProperties.secPerStep;
577        }
578}
579
580function fence(center, zone)
581{
582        return Math.min(Math.max(0+zone,center),World.wrldsiz-zone); //add and subtract zone from the world size to prevent reticulopodia from crossing the fence
583}
584
585function foramMove(cr)
586{
587        //are there any nutrients in zone 1 or 2?
588        {
589                var moved = stepToNearest(cr); //TODO weighted sum of distance and energy
590                if (moved==1)
591                {
592                        moveReticulopodia(cr);
593                        return;
594                }
595        }
596
597        //Prevents forams from crossing the world border. In the case of touching the border with the reticulopodia direction of the movement should be changed.
598        var change_direction = 0;
599        var new_x = fence(cr.bboxCenter.x, getZoneRange(cr, 1));
600        var new_y = fence(cr.bboxCenter.y, getZoneRange(cr, 1));
601
602        if ((new_x != cr.bboxCenter.x) || (new_y != cr.bboxCenter.y) || (cr.data->lifeparams->dir_counter >= int(secToSimSteps(ExpProperties.dir_change_sec))))
603        {
604                change_direction = 1;
605                cr.locationSetBboxLow(new_x-cr.bboxSize.x/2, new_y-cr.bboxSize.y/2, -cr.getPart(cr.numparts-1).sx);//place slightly under the bottom surface ("z" value depends on the size of the last=largest chamber)
606        }
607
608        //no nutrients in zone 2
609        if (getGene(cr, "hibernation",0) == 1)
610        {
611                reverseHib(cr);
612                cr.drive = XYZ.new(0,0,0);
613        }
614        //random move
615        else if (change_direction == 1)
616        {
617                cr.data->lifeparams->dir = randomDir();
618                cr.data->lifeparams->dir_counter = 0;
619                cr.drive = cr.data->lifeparams->dir;
620                moveEnergyDec(cr);
621        }
622        else
623        {
624                cr.drive = cr.data->lifeparams->dir;
625        }
626        moveReticulopodia(cr);
627}
628
629function moveReticulopodia(cr)
630{
631        if (visualization(cr))
632        {
633                cr.data->reticulopodiacreature.locationSetBboxLow(cr.bboxCenter.x-getZoneRange(cr,1), cr.bboxCenter.y-getZoneRange(cr,1), cr.bboxCenter.z-getZoneRange(cr,1));
634                cr.data->reticulopodiacreature.drive = cr.drive;
635        }
636}
637
638function randomDir()
639{
640        var dir = (Math.rndUni(-ExpProperties.zone2_range, ExpProperties.zone2_range), Math.rndUni(-ExpProperties.zone2_range, ExpProperties.zone2_range), 0); 
641        dir.normalize();
642        dir.scale(-1*movePerStep);
643        return dir;
644}
645
646function energyTransfer(cr1, cr2)
647{
648        cr1.drive = XYZ.new(0,0,0);
649        var e =  ExpProperties.feedtrans*cr1.energy*ExpProperties.secPerStep; //TODO efficiency dependent on age
650        //Simulator.print("transferring "+e +"("+e*ExpProperties.ingestion+")"+" to "+cr1.name +" ("+ cr1.energy+") " +" from "+cr2.uid+" ("+cr2.energy+") "+ e/ExpProperties.secPerStep+ " per sec");
651        var transferred = cr2.transferEnergyTo(cr1, e);
652        cr1.energy -= transferred*(1-ExpProperties.ingestion);
653        if (cr1.data->lifeparams->hibernated == 1)
654        {
655                reverseHib(cr1);
656        }
657}
658
659function reverseHib(cr)
660{
661        if (cr.data->lifeparams->hibernated == 1)
662        {
663                setForamMeta(cr); //unhibernate
664        }
665        else
666        {
667                cr.idleen = (ExpProperties.energy_hib * cr.energy)*ExpProperties.secPerStep; //hibernate
668        }
669        cr.data->lifeparams->hibernated = 1 - cr.data->lifeparams->hibernated;
670}
671
672function onForamsStep(cr)
673{
674        //checking for gametogenesis process
675        if (cr.data->lifeparams->division_time > 0)
676        {
677                cr.data->lifeparams->division_time = Math.max(cr.data->lifeparams->division_time-1,0);
678        }
679        //checking for end of gametogenesis
680        else if (cr.data->lifeparams->division_time == 0)
681        {
682                //waiting for gamets fusion
683        }
684        //checking for chamber growth process
685        else if (cr.data->lifeparams->chamber_growth > 0)
686        {
687                var chamber_time = Math.max(cr.data->lifeparams->chamber_growth-1,0);
688                cr.data->lifeparams->chamber_growth = chamber_time;
689                cr.energy -= ExpProperties.chamberCostPerSec * cr.energy * ExpProperties.secPerStep;
690
691                if (visualization(cr))
692                {
693                        visualizeChamberGrowth(cr, chamber_time);
694                }
695        }
696        //checking for end of the chamber growth process
697        else if (cr.data->lifeparams->chamber_growth == 0 && visualization(cr)==0)
698        {       
699                foramGrow(cr, lastChamberNum(cr), 1);
700                cr.data->lifeparams->chamber_growth = -1;
701                //Simulator.print("chamber "+ (lastChamberNum(cr) + 1) +" complete");
702        }
703        else
704        {
705                //update of metabolism rate
706                if (cr.data->lifeparams->hibernated == 0)
707                {
708                        setForamMeta(cr);
709                }
710
711                if (deathConditions(cr) == 1)
712                {
713                        if (ExpProperties.logging == 1)
714                        {
715                                log(createLogVector(cr, cr.data->lifeparams->max_energy_level),ExpProperties.logPref+"fossil_log.txt");
716                                log(createLogVector(cr, cr.lifespan),ExpProperties.logPref+"lifespan_log.txt");
717                        }                       
718                        Populations[0].kill(cr);
719                        return;
720                }
721
722                //update direction change counter
723                cr.data->lifeparams->dir_counter += 1;
724
725                foramMove(cr);
726
727                var repro = foramReproduce(cr);
728                if (repro == 1)
729                {
730                        return;
731                }
732
733                cr.data->lifeparams->max_energy_level = Math.max(cr.energy, cr.data->lifeparams->max_energy_level);
734
735                //cheking conditions of chamber growth process start
736                if  (lastChamberNum(cr) < max_chamber_volume[cr.data->lifeparams->gen].size)
737                {
738                        if ((cr.data->lifeparams->max_energy_level >= energyFromVolume(max_chamber_volume[cr.data->lifeparams->gen][lastChamberNum(cr)-1],0))) 
739                        {
740                                cr.data->lifeparams->chamber_growth = int(secToSimSteps(ExpProperties.chamberGrowthSec));
741                        }       
742                }
743        }       
744}
745
746function deathConditions(cr)
747{
748        if ((cr.energy <= getProperty(cr.data->lifeparams->gen,"e_death_level")*cr.data->lifeparams->max_energy_level) || (Math.rnd01 < ExpProperties.hunted_prob))
749        {
750                return 1;
751        }
752        else
753                return 0;
754}
755
756function onForamsDied(cr)
757{
758        if (visualization(cr))
759        {
760                Populations[2].delete(cr.data->reticulopodiacreature);
761        }
762        //fossilization
763        var geno = GenePools[0].add(cr.genotype);
764        geno.data->genes = cr.data->genes;
765        geno.data->lifeparams = cr.data->lifeparams;
766        if (ExpProperties.logging == 1) Simulator.print("\"" + cr.name + "\" died...");
767        ExpState.totaltestedcr++;
768}
769
770// --------------------------------foram end -------------------------------------
771
772// -------------------------------- nutrient begin --------------------------------
773
774function createNutrientGenotype(nutrientradius)
775{
776        return "//0\nm:Vstyle=nutrient\np:sh=3,sx="+nutrientradius+",sy="+nutrientradius+",sz="+nutrientradius+",ry=1.57,vr=0.0,1.0,0.0";
777}
778
779function onNutrientsStep(cr)
780{
781        cr.locationSetBboxLow(cr.bboxLow.x % World.wrldsiz, cr.bboxLow.y % World.wrldsiz, 0.5);
782}
783
784function addNutrient()
785{
786        var cr = Populations[1].add(createNutrientGenotype(ExpProperties.nutrientradius));
787
788        cr.name = "Nutrients";
789        cr.idleen = 0;
790        cr.energy0 = ExpProperties.energy_nut;
791        cr.energy = cr.energy0;
792        cr.signals.add("nutrient");
793
794        cr.signals[0].value = cr;
795
796        placeCreatureRandomly(cr, 0, 0);
797        if (ExpProperties.visualize == 1)
798        {
799                var nutsize = ExpProperties.nutrientradius*10;
800                var nut = Populations[2].add("//0\nm:Vstyle=nutrient_visual\np:sh=2,sx="+nutsize+",sy="+nutsize+",sz="+nutsize+",ry=1.5,vr=0.0,1.0,0.0");
801                cr.data->reticulopodiacreature = nut;
802                nut.locationSetBboxLow( cr.bboxLow.x+cr.bboxSize.x/2-nut.bboxSize.x/2,  cr.bboxLow.y+cr.bboxSize.y/2-nut.bboxSize.y/2, -nutsize);
803        }
804}
805
806function onNutrientsDied(cr)
807{
808        if (visualization(cr))
809        {
810                Populations[2].delete(cr.data->reticulopodiacreature);
811        }
812}
813
814function getNumberCounter(counter, increase, unitsize) //increase counter and then deduct and return an integer (=discrete) number of "full" units
815{
816        counter += increase;
817        var unitcount = int(counter/unitsize);
818        counter -= unitcount*unitsize;
819        return {"counter" : counter, "number" : unitcount};
820}
821
822function nutrientGrowth()
823{
824        if (ExpProperties.foodfluxChange > 0)
825        {
826                        changePeriod += 1;
827                        if (phase=="low" && changePeriod >= secToSimSteps(23328000)) //9 months
828                        {
829                                ExpProperties.foodflux = ExpProperties.foodflux/ExpProperties.foodfluxChange;
830                                phase = "high";
831                                changePeriod = 0;
832                        }
833               
834                        else if (phase == "high" && changePeriod >= secToSimSteps(7776000)) //3 months
835                        {
836                                ExpProperties.foodflux = ExpProperties.foodflux*ExpProperties.foodfluxChange;
837                                phase = "low";
838                                changePeriod = 0;
839                        }
840        }
841
842        var nutrientNum = getNumberCounter(nutrient_num_counter, ExpProperties.foodflux*wrldsizSquareMeters*ExpProperties.secPerStep,ExpProperties.energy_nut*0.000000000001);
843
844        nutrient_num_counter = nutrientNum["counter"];
845
846        for (var i = 0; i < nutrientNum["number"]; i++)
847        {   
848                addNutrient();
849        }
850
851        if (ExpProperties.logging == 1 && nutrientNum["number"] > 0)
852        {
853                log([nutrientNum["number"]],ExpProperties.logPref+"nutrients_log.txt");
854        }
855
856}
857
858// -------------------------------- nutrient end --------------------------------
859
860// -------------------------------- step begin --------------------------------
861
862function onStep()
863{
864
865        nutrientGrowth();
866        if (ExpProperties.logging == 1)
867        {
868                createStatistics();
869        }
870
871        //reproduction --------------------------------------------
872        reprocounter += 1;
873        if (reprocounter > secToSimSteps(ExpProperties.reproTimeSec))
874        {
875                reprocounter = 0;
876                for (var s = 0; s < species_genes.size; s++)
877                {
878                        reproduce_parents(s);
879                }
880               
881        }
882
883        //check for extinction -----------------------------------------------
884        if (Populations[0].size == 0)
885        {
886                if (ExpProperties.autorestart)
887                {
888                        Simulator.print("no more creatures, restarting...");
889                        onExpInit();
890                }
891                else
892                {
893                        Simulator.print("no more creatures, stopped.");
894                        Simulator.stop();
895                }
896        }
897        if (ExpProperties.maxSteps > 0)
898        {
899                if (Simulator.stepNumber >= ExpProperties.maxSteps)
900                        Simulator.stop();
901        }
902}
903
904function createStatistics()
905{       
906        var number = [];
907        var e_inc = [];
908        var e_nut = 0.0;
909
910        for (var s = 0; s < species_genes.size; s++)
911        {
912                number.add([0,0]);// [haplo][diplo]
913                e_inc.add([0,0]);
914        }
915
916        for (var i = 0; i < Populations[0].size; i++)
917        {
918                var cr = Populations[0].get(i);
919                var gen = cr.data->lifeparams->gen;
920                var species = cr.data->lifeparams->species;
921
922                number[species][gen] = number[species][gen] + 1;
923                e_inc[species][gen] = e_inc[species][gen] + cr.energy;
924        }
925
926        for (var i = 0; i < Populations[1].size; i++)
927        {
928                var cr = Populations[1].get(i);
929                e_nut += cr.energy;
930        }
931
932        var log_numbers = [];
933        var log_energies = [];
934
935        for (var s = 0; s < species_genes.size; s++)
936        {
937                for (var p = 0; p < 2; p++)
938                {
939                        log_numbers.add(number[s][p]);
940                        log_energies.add(e_inc[s][p]);
941                }
942        }
943       
944        log_numbers.add(Populations[1].size);
945        log_energies.add(e_nut);
946
947        log(log_numbers, ExpProperties.logPref+"forams_log.txt");
948    log(log_energies,  ExpProperties.logPref+"energies_log.txt");
949}
950
951function log(tolog, fname)
952{
953        var f = File.appendDirect(fname, "forams data");
954        f.writeString("" + Simulator.stepNumber);
955        for (var  i = 0; i < tolog.size; i++)
956        {
957                f.writeString(";" + tolog[i]);
958        }
959        f.writeString("\n");
960        f.close();
961}
962
963function createLogVector(cr, value)
964{
965        var vec = Vector.new();
966        for (var i = 0; i < species_genes.size; i++)
967        {
968                for (var j = 0; j < 2; j++)
969                {
970                        vec.add(0);
971                }
972                if (cr.data->lifeparams->species == i)
973                {
974                        vec[i*2+cr.data->lifeparams->gen] = value;             
975                }
976        }
977        return vec;
978}
979
980
981// -------------------------------- step end --------------------------------
982//TODO default params values in frams instead of microns/seconds
983
984@include "standard_events.inc"
985
986~
987
988property:
989id:visualize
990name:Show reticulopodia and nutrients
991type:d 0 1 0
992group:
993
994property:
995id:maxSteps
996name:Maximum number of steps
997type:d 0 10000000 0
998group:
999
1000property:
1001id:scalingFactor
1002name:Scaling factor for micrometers
1003type:f 0 -1 0.01
1004group:
1005
1006property:
1007id:logging
1008name:Log statistics to file
1009type:d 0 1 0
1010group:
1011
1012property:
1013id:logPref
1014name:Log prefix
1015type:s
1016
1017property:
1018id:secPerStep
1019name:Seconds per simulation step
1020help:~
1021Number of seconds of foraminifera time per simulation step.
1022Lower values mean smoother animation.~
1023type:f 1 480 300
1024flags: 16
1025group:
1026
1027property:
1028id:foramSpeedMmPerMin
1029name:Speed of foraminfera in mm/min
1030type:f 0.01 0.1 0.05
1031flags: 16
1032group:Foraminifera
1033
1034property:
1035id:dir_change_sec
1036name:Number of seconds before direction change
1037type:d 300 300000 6000
1038group:Foraminifera
1039
1040property:
1041id:foramPop
1042name:Initial forams population size
1043type:d 1 1000 20
1044group:Foraminifera
1045
1046property:
1047id:gametoPeriodSec
1048name:Time of gametogenesis
1049type:f 300 300000 21600
1050group:Reproduction
1051
1052property:
1053id:gametSuccessRate
1054name:Ratio of successful gamets
1055type:f 0.0001 0.01 0.001
1056group:Reproduction
1057
1058property:
1059id:divisionCost
1060name:Cost of division in pG
1061type:f 15 25 20
1062group:Reproduction
1063
1064property:
1065id:min_repro_energ_haplo
1066name:Min reproduction energy of haploid in pg
1067type:f 0 -1 350000
1068group:Energy
1069
1070property:
1071id:min_repro_energ_diplo
1072name:Min reproduction energy of diploid in pg
1073type:f 0 -1 600000
1074group:Energy
1075
1076property:
1077id:repro_prob
1078name:Probability of reproduction
1079type:f 0 1 0.8
1080group:Reproduction
1081
1082property:
1083id:energies0_haplo
1084name:Energy of offspring from diploid forams
1085type:f 0 -1 20
1086group:Energy
1087
1088property:
1089id:energies0_diplo
1090name:Energy of offspring from diploid forams
1091type:f 0 -1 1.25
1092group:Energy
1093
1094property:
1095id:max_chamber_num_haplo
1096name:Maximum number of haploid chambers
1097type:f 1 50 35
1098group:Energy
1099
1100property:
1101id:max_chamber_num_diplo
1102name:Maximum number of diploid chambers
1103type:f 1 50 35
1104group:Energy
1105
1106property:
1107id:crossprob
1108name:Crossover probability
1109type:f 0 1 0
1110group:Reproduction
1111
1112property:
1113id:mutationprob
1114name:Mutation probability
1115type:f 0 1 0
1116group:Reproduction
1117
1118property:
1119id:reproTimeSec
1120name:Time before reproduction
1121type:d 0 10000 720
1122group:Reproduction
1123
1124property:
1125id:chamberGrowthSec
1126name:Time of the chamber growth in seconds
1127type:f 720 43200 43200
1128group:Foraminifera
1129
1130property:
1131id:chamber_proculus_haplo
1132name:Size of proculus
1133type:f
1134group:Foraminifera
1135
1136property:
1137id:chamber_proculus_diplo
1138name:Size of proculus
1139type:f
1140group:Foraminifera
1141
1142property:
1143id:hunted_prob
1144name:Probability of being hunted
1145type:f 0 1 0
1146group:Foraminifera
1147
1148property:
1149id:zone1_range
1150name:Zone 1 range in frams units
1151type:f 0 200 10
1152group:Foraminifera
1153
1154property:
1155id:zone2_range
1156name:Zone 2 range in frams units
1157type:f 0 3000 30
1158group:Foraminifera
1159
1160property:
1161id:chamberCostPerSec
1162name:Cost of growning chamber per second
1163type:f 0 1 0.000001
1164group:Energy
1165
1166property:
1167id:e_death_level_haplo
1168name:Minimal level of energy to sustain life of haploid
1169type:f 0 1 0.5
1170group:Energy
1171
1172property:
1173id:e_death_level_diplo
1174name:Minimal level of energy to sustain life of diploid
1175type:f 0 1 0.5
1176group:Energy
1177
1178property:
1179id:energy_hib
1180name:Energy used for hibernation during one step
1181type:f 0 1 0.0000001
1182group:Energy
1183
1184property:
1185id:energy_move
1186name:Energy used for movement during one step
1187type:f 0 1 0.0000005
1188group:Energy
1189
1190property:
1191id:e_meta
1192name:Idle metabolism
1193type:f 0 1 0.0000005
1194group:Energy
1195help:Foraminifera consumes this proportion of its energy in one time step
1196
1197property:
1198id:ingestion
1199name:Ingestion rate
1200type:f 0 -1 0.25
1201group:Energy
1202
1203property:
1204id:nutrient_pop
1205name:Nutrient population
1206type:f 0 1000000
1207group:Energy
1208help:How fast energy is created in the world
1209
1210property:
1211id:energy_nut
1212name:Nutrient energy
1213type:f 0 10000000
1214group:Energy
1215
1216property:
1217id:nutrientradius
1218name:Nutrient size
1219type:f 0.001 0.9 0.1
1220group:Energy
1221
1222property:
1223id:picoCarbonPerMikro
1224name:Picograms of carbon in cubic micrometer
1225type:f 0 -1 0.13
1226group:Energy
1227
1228property:
1229id:feedtrans
1230name:Energy transfer per second
1231type:f 0 1 0.001
1232group:Energy
1233
1234property:
1235id:foodflux
1236name:POM flux in grams per second per square meter
1237type:f 0 1 0.0000000075631
1238group:Energy
1239
1240property:
1241id:foodfluxChange
1242name:Set variable feed rate
1243type:f 0 -1 0
1244group:Energy
1245
1246property:
1247id:stress
1248name:Environmental stress
1249type:d 0 1 1
1250group:
1251
1252property:
1253id:repro_trigger
1254name:Reproduction trigger
1255type:d 0 1 1
1256group:Reproduction
1257
1258property:
1259id:creath
1260name:Creation height
1261type:f -1 50 -0.99
1262help:~
1263Vertical position (above the surface) where new Forams are revived.
1264Negative values are only used in the water area:
1265  0   = at the surface
1266-0.5 = half depth
1267-1   = just above the bottom~
1268
1269property:
1270id:autorestart
1271name:Restart after extinction
1272help:Restart automatically this experiment after the last creature has died?
1273type:d 0 1 0
1274
1275state:
1276id:nutrient
1277name:Nutrient locations
1278help:vector of vectors [x,y,energy]
1279type:x
1280flags:32
1281
1282state:
1283id:notes
1284name:Notes
1285type:s 1
1286help:~
1287You can write anything here
1288(it will be saved to the experiment file)~
1289
1290state:
1291id:totaltestedcr
1292name:Evaluated Forams
1293help:Total number of the Forams evaluated in the experiment
1294type:d
1295flags:16
Note: See TracBrowser for help on using the repository browser.