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

Last change on this file since 1329 was 1329, checked in by Maciej Komosinski, 4 days ago

Cosmetic

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