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

Last change on this file since 590 was 590, checked in by oriona, 8 years ago

Feed period changed to food flux in grams per square meter per second. Theater parameters updated.

File size: 31.9 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.center_x, g.data->genes[1] - cr.center_y, 0);
203                                cr.energy = g.data->genes[2];
204                        }
205                        else
206                        {
207                                cr.move(Math.rnd01 * World.wrldsiz - cr.center_x, Math.rnd01 * World.wrldsiz - cr.center_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.center_x, cr.center_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 addForam(species, iter, start_energy, ploid)
326{
327        var chambernum =  chamberNumFromEnergy(start_energy, ploid);
328        var radius = getPloidRadius(ploid);
329        var geno = create_genotype(radius, chambernum, colors[ploid], 1);
330        curColor = colors[ploid];
331        var cr = Populations[0].add(geno);
332        cr.name = "Initial creature" + species + "_" + iter;
333        placeRandomlyNotColliding(cr);
334        cr.energy = start_energy;
335        setGenotype({"opt" : "birth", "cr" : cr, "gen" : ploid, "species" : species, "energy0" : cr.energy, "genes" : species_genes[species], "parentsuids" : ["c0"]});
336        if (ploid == 1)
337        {
338                cr.data->genes = [cr.data->genes, cr.data->genes]; //TODO two different genes sets
339        }
340        moveReticulopodia(cr);
341}
342
343function addInitialForam(species, iter)
344{
345        var ploid = 0;
346        if (Math.rnd01 > 0.5)
347        {
348                ploid = 1;
349        }       
350        //add new foram with random energy bewtween starting energy and reproduction threshold
351        var repro_thr = species_genes[species]->min_repro_energies[ploid];
352        var start_energy = Math.rndUni(energyFromVolume(getPloidRadius(ploid),1),repro_thr-0.25*repro_thr);
353        addForam(species, iter, start_energy,ploid);
354}
355
356//new species can be added as a dictionary with parameter values that are different than default values
357function addSpecies(new_genes)
358{
359        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});
360        for (var i = 0; i < new_genes.size; i++)
361        {
362                var key = new_genes.getKey(i);
363                species_genes[species_genes.size-1][key] = new_genes[key];
364        }
365}
366
367// -------------------------------- foram begin -----------------------------------
368
369function setForamMeta(cr)
370{
371        //percent of current energy
372        cr.idleen = (ExpProperties.e_meta * cr.energy)*ExpProperties.secPerStep;
373}
374
375function lastChamberNum(cr)
376{
377        return cr.numparts;
378}
379
380function getZoneRange(cr, zone_num)
381{
382        return ExpProperties.["zone"+zone_num+"_range"];
383}
384
385function addReticulopodia(cr, radius)
386{
387                if (reticulopodiaExists(cr))
388                {
389                        Populations[2].delete(cr.data->reticulopodiacreature);
390                }
391                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");
392                cr.data->reticulopodiacreature = ret;
393                ret.getMechPart(0).orient.set(cr.getMechPart(0).orient);
394                ret.moveAbs(cr.center_x-radius, cr.center_y-radius, cr.center_z-radius);
395}
396
397function onForamsBorn(cr)
398{
399        setForamMeta(cr);
400        if (ExpProperties.visualize == 1)
401        {
402                addReticulopodia(cr, curRadius);
403                moveReticulopodia(cr);
404        }
405}
406
407function placeRandomlyNotColliding(cr)
408{
409        var retry = 100; //try 100 times
410        while (retry--)
411        {
412                placeCreatureRandomly(cr, 0, 0);
413                if (!cr.boundingBoxCollisions(0))
414                {
415                        cr.moveAbs(cr.pos_x, cr.pos_y, -cr.getPart(cr.numparts-1).sx); //place slightly under the bottom surface ("z" value depends on the size of the last=largest chamber)
416                        return cr;
417                }
418        }
419
420        Populations[0].delete(cr);
421}
422
423function reticulopodiaExists(cr)
424{
425        var has_ret = 0;
426
427        if (cr.data->reticulopodiacreature != null)
428        {
429                if (Populations[2].findUID(cr.data->reticulopodiacreature.uid) != null)
430                {
431                        has_ret = 1;
432                }
433        }
434
435        return has_ret;
436}
437
438function visualization(cr)
439{
440        return reticulopodiaExists(cr);
441}
442
443function foramGrow(cr, chamber_num, lastchambergrowth)
444{
445        if ((chamber_num+1) <= max_chamber_volume[cr.data->lifeparams->gen].size)
446        {
447                curColor = colors[cr.data->lifeparams->gen];
448                var ploid = cr.data->lifeparams->gen;
449                var geno = create_genotype(getPloidRadius(ploid), chamber_num+1, colors[ploid], lastchambergrowth);
450                var cr2 = Populations[0].add(geno);
451
452                cr2.energy0 = cr.energy;
453                cr2.energy = cr2.energy0;
454
455                setGenotype({"cr" : cr2, "parent_genes" : cr.data->genes, "parent_lifeparams" : cr.data->lifeparams, "opt" : "growth", "energy0" : cr.energy0});
456                cr2.moveAbs(cr.pos_x, cr.pos_y,cr.pos_z);
457                setForamMeta(cr2);
458
459                if (reticulopodiaExists(cr))
460                {
461                        Populations[2].delete(cr.data->reticulopodiacreature);
462                }
463                Populations[0].delete(cr);
464                return cr2;
465        }
466        return cr;
467}
468
469function visualizeChamberGrowth(cr, chamber_time)
470{
471        var total_time = secToSimSteps(ExpProperties.chamberGrowthSec);
472        var ret_unit = total_time/chamber_vis_denominator;
473        var chamber_unit = total_time-ret_unit;
474
475        if (chamber_time < ret_unit || chamber_time >= chamber_unit)
476        {
477                var new_rad = Math.min(Math.max((chamber_time%ret_unit)/ret_unit*getZoneRange(cr,1),0.01),getZoneRange(cr,1));
478
479                if(chamber_time < ret_unit)
480                {
481                        new_rad = getZoneRange(cr,1)-new_rad;
482                }
483
484                curColor = colors[cr.data->lifeparams->gen];
485                addReticulopodia(cr,new_rad);
486
487                if (chamber_time == 0)//checking for end of chamber growth process
488                {
489                        cr.data->lifeparams->chamber_growth = -1;       
490                }
491        }
492        else
493        {
494                var new_rad = 1 - Math.min(Math.max((chamber_time-ret_unit)/chamber_unit,0.01),1);
495                curRadius = cr.data->reticulopodiacreature.getPart(1).sy;
496                               
497                if (chamber_time == ret_unit)
498                {
499                        new_rad = 1;
500                }
501
502                var new_cr = foramGrow(cr, chamberNumFromEnergy(cr.data->lifeparams->max_energy_level, cr.data->lifeparams->gen)-1, new_rad);
503                curRadius = getZoneRange(new_cr,1);
504        }
505}
506
507function stepToNearest(cr)
508{
509        var p = cr.getMechPart(0);
510        var n = cr.signals.receiveSet("nutrient", getZoneRange(cr,2));
511
512        //if signals are received find the source of the nearest
513        if (n.size > 0)
514        {
515                var i;
516                var mp;
517                var distvec = XYZ.new(0, 0, 0);
518                var dist;
519                var mindist = 100000000000.0;
520                var mindistvec = null;
521                var eating = 0;
522
523                for (i = 0; i < n.size; i++)
524                {
525                        mp = n[i].value.getMechPart(0);
526                        distvec.set(mp.pos);
527                        distvec.sub(p.pos);
528                        dist = distvec.length;
529                        if (dist < getZoneRange(cr,1))
530                        {
531                                if (n[i].value != null)
532                                {
533                                        energyTransfer(cr, n[i].value);
534                                        eating = 1;
535                                }
536                        }
537                        else if (eating == 0 && cr.data->lifeparams->hibernated == 0 && dist < mindist)
538                        {
539                                mindist = dist;
540                                mindistvec = distvec.clone();
541                        }
542                }
543
544                if (!eating && cr.data->lifeparams->hibernated == 0)
545                {
546                        mindistvec.z = 0;
547                        mindistvec.normalize();
548                        mindistvec.scale(-1*movePerStep);
549                        cr.localDrive = mindistvec;
550                        moveEnergyDec(cr);
551                }
552
553                return 1;
554        }
555       
556        else
557        {
558                return 0;
559        }
560}
561
562function moveEnergyDec(cr)
563{
564        if (cr.data->lifeparams->hibernated == 0)
565        {
566                //percent of maximal energy
567                cr.energy -= (ExpProperties.energy_move * cr.data->lifeparams->max_energy_level)*ExpProperties.secPerStep;
568        }
569}
570
571function fence(center, zone)
572{
573        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
574}
575
576function foramMove(cr)
577{
578        //are there any nutrients in zone 1 or 2?
579        {
580                var moved = stepToNearest(cr); //TODO weighted sum of distance and energy
581                if (moved==1)
582                {
583                        moveReticulopodia(cr);
584                        return;
585                }
586        }
587
588        //Prevents forams from crossing the world border. In the case of touching the border with the reticulopodia direction of the movement should be changed.
589        var change_direction = 0;
590        var new_x = fence(cr.center_x, getZoneRange(cr, 1));
591        var new_y = fence(cr.center_y, getZoneRange(cr, 1));
592
593        if ((new_x != cr.center_x) || (new_y != cr.center_y) || (cr.data->lifeparams->dir_counter >= int(secToSimSteps(ExpProperties.dir_change_sec))))
594        {
595                change_direction = 1;
596                cr.moveAbs(new_x-cr.size_x/2, new_y-cr.size_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)
597        }
598
599        //no nutrients in zone 2
600        if (getGene(cr, "hibernation",0) == 1)
601        {
602                reverseHib(cr);
603                cr.localDrive = XYZ.new(0,0,0);
604        }
605        //random move
606        else if (change_direction == 1)
607        {
608                cr.data->lifeparams->dir = randomDir();
609                cr.data->lifeparams->dir_counter = 0;
610                cr.localDrive = cr.data->lifeparams->dir;
611                moveEnergyDec(cr);
612        }
613        else
614        {
615                cr.localDrive = cr.data->lifeparams->dir;
616        }
617        moveReticulopodia(cr);
618}
619
620function moveReticulopodia(cr)
621{
622        if (visualization(cr))
623        {
624                cr.data->reticulopodiacreature.moveAbs(cr.center_x-getZoneRange(cr,1), cr.center_y-getZoneRange(cr,1), cr.center_z-getZoneRange(cr,1));
625                cr.data->reticulopodiacreature.localDrive = cr.localDrive;
626        }
627}
628
629function randomDir()
630{
631        var dir = (Math.rndUni(-ExpProperties.zone2_range, ExpProperties.zone2_range), Math.rndUni(-ExpProperties.zone2_range, ExpProperties.zone2_range), 0); 
632        dir.normalize();
633        dir.scale(-1*movePerStep);
634        return dir;
635}
636
637function energyTransfer(cr1, cr2)
638{
639        cr1.localDrive = XYZ.new(0,0,0);
640        var e =  ExpProperties.feedtrans*cr1.energy*ExpProperties.secPerStep; //TODO efficiency dependent on age
641        //Simulator.print("transferring "+e +"("+e*ExpProperties.ingestion+")"+" to "+cr1.name +" ("+ cr1.energy+") " +" from "+cr2.uid+" ("+cr2.energy+") "+ e/ExpProperties.secPerStep+ " per sec");
642        var transferred = cr2.transferEnergyTo(cr1, e);
643        cr1.energy -= transferred*(1-ExpProperties.ingestion);
644        if (cr1.data->lifeparams->hibernated == 1)
645        {
646                reverseHib(cr1);
647        }
648}
649
650function reverseHib(cr)
651{
652        if (cr.data->lifeparams->hibernated == 1)
653        {
654                setForamMeta(cr); //unhibernate
655        }
656        else
657        {
658                cr.idleen = (ExpProperties.energy_hib * cr.energy)*ExpProperties.secPerStep; //hibernate
659        }
660        cr.data->lifeparams->hibernated = 1 - cr.data->lifeparams->hibernated;
661}
662
663function onForamsStep(cr)
664{
665        //checking for gametogenesis process
666        if (cr.data->lifeparams->division_time > 0)
667        {
668                cr.data->lifeparams->division_time = Math.max(cr.data->lifeparams->division_time-1,0);
669        }
670        //checking for end of gametogenesis
671        else if (cr.data->lifeparams->division_time == 0)
672        {
673                //waiting for gamets fusion
674        }
675        //checking for chamber growth process
676        else if (cr.data->lifeparams->chamber_growth > 0)
677        {
678                var chamber_time = Math.max(cr.data->lifeparams->chamber_growth-1,0);
679                cr.data->lifeparams->chamber_growth = chamber_time;
680                cr.energy -= ExpProperties.chamberCostPerSec * cr.energy * ExpProperties.secPerStep;
681
682                if (visualization(cr))
683                {
684                        visualizeChamberGrowth(cr, chamber_time);
685                }
686        }
687        //checking for end of the chamber growth process
688        else if (cr.data->lifeparams->chamber_growth == 0 && visualization(cr)==0)
689        {       
690                foramGrow(cr, lastChamberNum(cr), 1);
691                cr.data->lifeparams->chamber_growth = -1;
692                //Simulator.print("chamber "+ (lastChamberNum(cr) + 1) +" complete");
693        }
694        else
695        {
696                //update of metabolism rate
697                if (cr.data->lifeparams->hibernated == 0)
698                {
699                        setForamMeta(cr);
700                }
701
702                if (deathConditions(cr) == 1)
703                {
704                        if (ExpProperties.logging == 1)
705                        {
706                                log(createLogVector(cr, cr.data->lifeparams->max_energy_level),ExpProperties.logPref+"fossil_log.txt");
707                                log(createLogVector(cr, cr.lifespan),ExpProperties.logPref+"lifespan_log.txt");
708                        }                       
709                        Populations[0].kill(cr);
710                        return;
711                }
712
713                //update direction change counter
714                cr.data->lifeparams->dir_counter += 1;
715
716                foramMove(cr);
717
718                var repro = foramReproduce(cr);
719                if (repro == 1)
720                {
721                        return;
722                }
723
724                cr.data->lifeparams->max_energy_level = Math.max(cr.energy, cr.data->lifeparams->max_energy_level);
725
726                //cheking conditions of chamber growth process start
727                if  (lastChamberNum(cr) < max_chamber_volume[cr.data->lifeparams->gen].size)
728                {
729                        if ((cr.data->lifeparams->max_energy_level >= energyFromVolume(max_chamber_volume[cr.data->lifeparams->gen][lastChamberNum(cr)-1],0))) 
730                        {
731                                cr.data->lifeparams->chamber_growth = int(secToSimSteps(ExpProperties.chamberGrowthSec));
732                        }       
733                }
734        }       
735}
736
737function deathConditions(cr)
738{
739        if ((cr.energy <= getProperty(cr.data->lifeparams->gen,"e_death_level")*cr.data->lifeparams->max_energy_level) || (Math.rnd01 < ExpProperties.hunted_prob))
740        {
741                return 1;
742        }
743        else
744                return 0;
745}
746
747function onForamsDied(cr)
748{
749        if (visualization(cr))
750        {
751                Populations[2].delete(cr.data->reticulopodiacreature);
752        }
753        //fossilization
754        var geno = GenePools[0].add(cr.genotype);
755        geno.data->genes = cr.data->genes;
756        geno.data->lifeparams = cr.data->lifeparams;
757        if (ExpProperties.logging == 1) Simulator.print("\"" + cr.name + "\" died...");
758        ExpState.totaltestedcr++;
759}
760
761// --------------------------------foram end -------------------------------------
762
763// -------------------------------- nutrient begin --------------------------------
764
765function createNutrientGenotype(nutrientradius)
766{
767        return "//0\nm:Vstyle=nutrient\np:sh=3,sx="+nutrientradius+",sy="+nutrientradius+",sz="+nutrientradius+",ry=1.57,vr=0.0,1.0,0.0";
768}
769
770function onNutrientsStep(cr)
771{
772        cr.moveAbs(cr.pos_x % World.wrldsiz, cr.pos_y % World.wrldsiz, 0.5);
773}
774
775function addNutrient()
776{
777        var cr = Populations[1].add(createNutrientGenotype(ExpProperties.nutrientradius));
778
779        cr.name = "Nutrients";
780        cr.idleen = 0;
781        cr.energy0 = ExpProperties.energy_nut;
782        cr.energy = cr.energy0;
783        cr.signals.add("nutrient");
784
785        cr.signals[0].value = cr;
786
787        placeCreatureRandomly(cr, 0, 0);
788        if (ExpProperties.visualize == 1)
789        {
790                var nutsize = ExpProperties.nutrientradius*10;
791                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");
792                cr.data->reticulopodiacreature = nut;
793                nut.moveAbs( cr.pos_x+cr.size_x/2-nut.size_x/2,  cr.pos_y+cr.size_y/2-nut.size_y/2, -nutsize);
794        }
795}
796
797function onNutrientsDied(cr)
798{
799        if (visualization(cr))
800        {
801                Populations[2].delete(cr.data->reticulopodiacreature);
802        }
803}
804
805function getNumberCounter(counter, increase, unit)
806{
807        var result = 0;
808        counter += increase;
809        result = int(counter/unit);
810        counter -= result*unit;
811        return {"counter" : counter, "number" : result};
812}
813
814function nutrientGrowth()
815{
816        if (ExpProperties.foodfluxChange > 0)
817        {
818                        changePeriod += 1;
819                        if (phase=="low" && changePeriod >= secToSimSteps(23328000)) //9 months
820                        {
821                                ExpProperties.foodflux = ExpProperties.foodflux/ExpProperties.foodfluxChange;
822                                phase = "high";
823                                changePeriod = 0;
824                        }
825               
826                        else if (phase == "high" && changePeriod >= secToSimSteps(7776000)) //3 months
827                        {
828                                ExpProperties.foodflux = ExpProperties.foodflux*ExpProperties.foodfluxChange;
829                                phase = "low";
830                                changePeriod = 0;
831                        }
832        }
833
834        var nutrientNum = getNumberCounter(nutrient_num_counter, ExpProperties.foodflux*wrldsizSquareMeters*ExpProperties.secPerStep,ExpProperties.energy_nut*0.000000000001);
835
836        nutrient_num_counter = nutrientNum["counter"];
837
838        for (var i = 0; i < nutrientNum["number"]; i++)
839        {   
840                addNutrient();
841        }
842
843        if (ExpProperties.logging == 1 && nutrientNum["number"] > 0)
844        {
845                log([nutrientNum["number"]],ExpProperties.logPref+"nutrients_log.txt");
846        }
847
848}
849
850// -------------------------------- nutrient end --------------------------------
851
852// -------------------------------- step begin --------------------------------
853
854function onStep()
855{
856
857        nutrientGrowth();
858        if (ExpProperties.logging == 1)
859        {
860                createStatistics();
861        }
862
863        //reproduction --------------------------------------------
864        reprocounter += 1;
865        if (reprocounter > secToSimSteps(ExpProperties.reproTimeSec))
866        {
867                reprocounter = 0;
868                for (var s = 0; s < species_genes.size; s++)
869                {
870                        reproduce_parents(s);
871                }
872               
873        }
874
875        //check for extinction -----------------------------------------------
876        if (Populations[0].size == 0)
877        {
878                if (ExpProperties.autorestart)
879                {
880                        Simulator.print("no more creatures, restarting...");
881                        onExpInit();
882                }
883                else
884                {
885                        Simulator.print("no more creatures, stopped.");
886                        Simulator.stop();
887                }
888        }
889        if (ExpProperties.maxSteps > 0)
890        {
891                if (Simulator.stepNumber >= ExpProperties.maxSteps)
892                        Simulator.stop();
893        }
894}
895
896function createStatistics()
897{       
898        var number = [];
899        var e_inc = [];
900        var e_nut = 0.0;
901
902        for (var s = 0; s < species_genes.size; s++)
903        {
904                number.add([0,0]);// [haplo][diplo]
905                e_inc.add([0,0]);
906        }
907
908        for (var i = 0; i < Populations[0].size; i++)
909        {
910                var cr = Populations[0].get(i);
911                var gen = cr.data->lifeparams->gen;
912                var species = cr.data->lifeparams->species;
913
914                number[species][gen] = number[species][gen] + 1;
915                e_inc[species][gen] = e_inc[species][gen] + cr.energy;
916        }
917
918        for (var i = 0; i < Populations[1].size; i++)
919        {
920                var cr = Populations[1].get(i);
921                e_nut += cr.energy;
922        }
923
924        var log_numbers = [];
925        var log_energies = [];
926
927        for (var s = 0; s < species_genes.size; s++)
928        {
929                for (var p = 0; p < 2; p++)
930                {
931                        log_numbers.add(number[s][p]);
932                        log_energies.add(e_inc[s][p]);
933                }
934        }
935       
936        log_numbers.add(Populations[1].size);
937        log_energies.add(e_nut);
938
939        log(log_numbers, ExpProperties.logPref+"forams_log.txt");
940    log(log_energies,  ExpProperties.logPref+"energies_log.txt");
941}
942
943function log(tolog, fname)
944{
945        var f = File.appendDirect(fname, "forams data");
946        f.writeString("" + Simulator.stepNumber);
947        for (var  i = 0; i < tolog.size; i++)
948        {
949                f.writeString(";" + tolog[i]);
950        }
951        f.writeString("\n");
952        f.close();
953}
954
955function createLogVector(cr, value)
956{
957        var vec = Vector.new();
958        for (var i = 0; i < species_genes.size; i++)
959        {
960                for (var j = 0; j < 2; j++)
961                {
962                        vec.add(0);
963                }
964                if (cr.data->lifeparams->species == i)
965                {
966                        vec[i*2+cr.data->lifeparams->gen] = value;             
967                }
968        }
969        return vec;
970}
971
972
973// -------------------------------- step end --------------------------------
974//TODO default params values in frams instead of microns/seconds
975
976@include "standard_events.inc"
977
978~
979
980property:
981id:visualize
982name:Show reticulopodia and nutrients
983type:d 0 1 0
984group:
985
986property:
987id:maxSteps
988name:Maximum number of steps
989type:d 0 10000000 0
990group:
991
992property:
993id:scalingFactor
994name:Scaling factor for micrometers
995type:f 0 -1 0.01
996group:
997
998property:
999id:logging
1000name:Log statistics to file
1001type:d 0 1 0
1002group:
1003
1004property:
1005id:logPref
1006name:Log prefix
1007type:s
1008
1009property:
1010id:secPerStep
1011name:Seconds per simulation step
1012help:~
1013Number of seconds of foraminifera time per simulation step.
1014Lower values mean smoother animation.~
1015type:f 1 480 300
1016flags: 16
1017group:
1018
1019property:
1020id:foramSpeedMmPerMin
1021name:Speed of foraminfera in mm/min
1022type:f 0.01 0.1 0.05
1023flags: 16
1024group:Foraminifera
1025
1026property:
1027id:dir_change_sec
1028name:Number of seconds before direction change
1029type:d 300 300000 6000
1030group:Foraminifera
1031
1032property:
1033id:foramPop
1034name:Initial forams population size
1035type:d 1 1000 20
1036group:Foraminifera
1037
1038property:
1039id:gametoPeriodSec
1040name:Time of gametogenesis
1041type:f 300 300000 21600
1042group:Reproduction
1043
1044property:
1045id:gametSuccessRate
1046name:Ratio of successful gamets
1047type:f 0.0001 0.01 0.001
1048group:Reproduction
1049
1050property:
1051id:divisionCost
1052name:Cost of division in pG
1053type:f 15 25 20
1054group:Reproduction
1055
1056property:
1057id:min_repro_energ_haplo
1058name:Min reproduction energy of haploid in pg
1059type:f 0 -1 350000
1060group:Energy
1061
1062property:
1063id:min_repro_energ_diplo
1064name:Min reproduction energy of diploid in pg
1065type:f 0 -1 600000
1066group:Energy
1067
1068property:
1069id:repro_prob
1070name:Probability of reproduction
1071type:f 0 1 0.8
1072group:Reproduction
1073
1074property:
1075id:energies0_haplo
1076name:Energy of offspring from diploid forams
1077type:f 0 -1 20
1078group:Energy
1079
1080property:
1081id:energies0_diplo
1082name:Energy of offspring from diploid forams
1083type:f 0 -1 1.25
1084group:Energy
1085
1086property:
1087id:max_chamber_num_haplo
1088name:Maximum number of haploid chambers
1089type:f 1 50 35
1090group:Energy
1091
1092property:
1093id:max_chamber_num_diplo
1094name:Maximum number of diploid chambers
1095type:f 1 50 35
1096group:Energy
1097
1098property:
1099id:crossprob
1100name:Crossover probability
1101type:f 0 1 0
1102group:Reproduction
1103
1104property:
1105id:mutationprob
1106name:Mutation probability
1107type:f 0 1 0
1108group:Reproduction
1109
1110property:
1111id:reproTimeSec
1112name:Time before reproduction
1113type:d 0 10000 720
1114group:Reproduction
1115
1116property:
1117id:chamberGrowthSec
1118name:Time of the chamber growth in seconds
1119type:f 720 43200 43200
1120group:Foraminifera
1121
1122property:
1123id:chamber_proculus_haplo
1124name:Size of proculus
1125type:f
1126group:Foraminifera
1127
1128property:
1129id:chamber_proculus_diplo
1130name:Size of proculus
1131type:f
1132group:Foraminifera
1133
1134property:
1135id:hunted_prob
1136name:Probability of being hunted
1137type:f 0 1 0
1138group:Foraminifera
1139
1140property:
1141id:zone1_range
1142name:Zone 1 range in frams units
1143type:f 0 200 10
1144group:Foraminifera
1145
1146property:
1147id:zone2_range
1148name:Zone 2 range in frams units
1149type:f 0 3000 30
1150group:Foraminifera
1151
1152property:
1153id:chamberCostPerSec
1154name:Cost of growning chamber per second
1155type:f 0 1 0.000001
1156group:Energy
1157
1158property:
1159id:e_death_level_haplo
1160name:Minimal level of energy to sustain life of haploid
1161type:f 0 1 0.5
1162group:Energy
1163
1164property:
1165id:e_death_level_diplo
1166name:Minimal level of energy to sustain life of diploid
1167type:f 0 1 0.5
1168group:Energy
1169
1170property:
1171id:energy_hib
1172name:Energy used for hibernation during one step
1173type:f 0 1 0.0000001
1174group:Energy
1175
1176property:
1177id:energy_move
1178name:Energy used for movement during one step
1179type:f 0 1 0.0000005
1180group:Energy
1181
1182property:
1183id:e_meta
1184name:Idle metabolism
1185type:f 0 1 0.0000005
1186group:Energy
1187help:Foraminifera consumes this proportion of its energy in one time step
1188
1189property:
1190id:ingestion
1191name:Ingestion rate
1192type:f 0 -1 0.25
1193group:Energy
1194
1195property:
1196id:nutrient_pop
1197name:Nutrient population
1198type:f 0 1000000
1199group:Energy
1200help:How fast energy is created in the world
1201
1202property:
1203id:energy_nut
1204name:Nutrient energy
1205type:f 0 10000000
1206group:Energy
1207
1208property:
1209id:nutrientradius
1210name:Nutrient size
1211type:f 0.001 0.9 0.1
1212group:Energy
1213
1214property:
1215id:picoCarbonPerMikro
1216name:Picograms of carbon in cubic micrometer
1217type:f 0 -1 0.13
1218group:Energy
1219
1220property:
1221id:feedtrans
1222name:Energy transfer per second
1223type:f 0 1 0.001
1224group:Energy
1225
1226property:
1227id:foodflux
1228name:POM flux in grams per second per square meter
1229type:f 0 1 0.0000000075631
1230group:Energy
1231
1232property:
1233id:foodfluxChange
1234name:Set variable feed rate
1235type:f 0 -1 0
1236group:Energy
1237
1238property:
1239id:stress
1240name:Environmental stress
1241type:d 0 1 1
1242group:
1243
1244property:
1245id:repro_trigger
1246name:Reproduction trigger
1247type:d 0 1 1
1248group:Reproduction
1249
1250property:
1251id:creath
1252name:Creation height
1253type:f -1 50 -0.99
1254help:~
1255Vertical position (above the surface) where new Forams are revived.
1256Negative values are only used in the water area:
1257  0   = at the surface
1258-0.5 = half depth
1259-1   = just above the bottom~
1260
1261property:
1262id:autorestart
1263name:Restart after extinction
1264help:Restart automatically this experiment after the last creature has died?
1265type:d 0 1 0
1266
1267state:
1268id:nutrient
1269name:Nutrient locations
1270help:vector of vectors [x,y,energy]
1271type:x
1272flags:32
1273
1274state:
1275id:notes
1276name:Notes
1277type:s 1
1278help:~
1279You can write anything here
1280(it will be saved to the experiment file)~
1281
1282state:
1283id:totaltestedcr
1284name:Evaluated Forams
1285help:Total number of the Forams evaluated in the experiment
1286type:d
1287flags:16
Note: See TracBrowser for help on using the repository browser.