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

Last change on this file since 1152 was 1152, checked in by Maciej Komosinski, 20 months ago

Foraminifera show has now smaller world compared to expdef (and adjusted other parameters), so it is better suited for visualization and demonstration

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 = 200;
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.