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

Last change on this file since 591 was 591, checked in by Maciej Komosinski, 8 years ago

Added a comment

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