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

Last change on this file since 908 was 908, checked in by Maciej Komosinski, 2 weeks ago

Updated for the new way of handling of dictionaries (where null is allowed as key's value)

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