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

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

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

File size: 31.9 KB
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
[590]805function getNumberCounter(counter, increase, unit)
806{
807        var result = 0;
808        counter += increase;
809        result = int(counter/unit);
810        counter -= result*unit;
811        return {"counter" : counter, "number" : result};
812}
813
[422]814function nutrientGrowth()
[380]815{
[590]816        if (ExpProperties.foodfluxChange > 0)
[481]817        {
818                        changePeriod += 1;
[554]819                        if (phase=="low" && changePeriod >= secToSimSteps(23328000)) //9 months
[481]820                        {
[590]821                                ExpProperties.foodflux = ExpProperties.foodflux/ExpProperties.foodfluxChange;
[481]822                                phase = "high";
823                                changePeriod = 0;
824                        }
825               
[554]826                        else if (phase == "high" && changePeriod >= secToSimSteps(7776000)) //3 months
[481]827                        {
[590]828                                ExpProperties.foodflux = ExpProperties.foodflux*ExpProperties.foodfluxChange;
[481]829                                phase = "low";
830                                changePeriod = 0;
831                        }
832        }
[422]833
[590]834        var nutrientNum = getNumberCounter(nutrient_num_counter, ExpProperties.foodflux*wrldsizSquareMeters*ExpProperties.secPerStep,ExpProperties.energy_nut*0.000000000001);
[493]835
[590]836        nutrient_num_counter = nutrientNum["counter"];
837
838        for (var i = 0; i < nutrientNum["number"]; i++)
839        {   
840                addNutrient();
[380]841        }
[493]842
[590]843        if (ExpProperties.logging == 1 && nutrientNum["number"] > 0)
844        {
845                log([nutrientNum["number"]],ExpProperties.logPref+"nutrients_log.txt");
846        }
847
[380]848}
849
[421]850// -------------------------------- nutrient end --------------------------------
[380]851
[422]852// -------------------------------- step begin --------------------------------
[380]853
[422]854function onStep()
855{
[432]856
857        nutrientGrowth();
[486]858        if (ExpProperties.logging == 1)
[422]859        {
860                createStatistics();
861        }
862
863        //reproduction --------------------------------------------
864        reprocounter += 1;
[554]865        if (reprocounter > secToSimSteps(ExpProperties.reproTimeSec))
[422]866        {
867                reprocounter = 0;
[567]868                for (var s = 0; s < species_genes.size; s++)
869                {
870                        reproduce_parents(s);
871                }
872               
[422]873        }
874
875        //check for extinction -----------------------------------------------
876        if (Populations[0].size == 0)
877        {
[486]878                if (ExpProperties.autorestart)
[422]879                {
880                        Simulator.print("no more creatures, restarting...");
881                        onExpInit();
882                }
883                else
884                {
885                        Simulator.print("no more creatures, stopped.");
886                        Simulator.stop();
887                }
888        }
[486]889        if (ExpProperties.maxSteps > 0)
[432]890        {
[486]891                if (Simulator.stepNumber >= ExpProperties.maxSteps)
[432]892                        Simulator.stop();
893        }
[422]894}
895
896function createStatistics()
897{       
[487]898        var number = [];
899        var e_inc = [];
[422]900        var e_nut = 0.0;
901
[487]902        for (var s = 0; s < species_genes.size; s++)
903        {
904                number.add([0,0]);// [haplo][diplo]
905                e_inc.add([0,0]);
906        }
907
[422]908        for (var i = 0; i < Populations[0].size; i++)
909        {
910                var cr = Populations[0].get(i);
[476]911                var gen = cr.data->lifeparams->gen;
912                var species = cr.data->lifeparams->species;
[430]913
914                number[species][gen] = number[species][gen] + 1;
915                e_inc[species][gen] = e_inc[species][gen] + cr.energy;
[422]916        }
917
918        for (var i = 0; i < Populations[1].size; i++)
919        {
920                var cr = Populations[1].get(i);
921                e_nut += cr.energy;
922        }
923
[487]924        var log_numbers = [];
925        var log_energies = [];
[422]926
[487]927        for (var s = 0; s < species_genes.size; s++)
928        {
929                for (var p = 0; p < 2; p++)
930                {
931                        log_numbers.add(number[s][p]);
932                        log_energies.add(e_inc[s][p]);
933                }
934        }
935       
936        log_numbers.add(Populations[1].size);
937        log_energies.add(e_nut);
938
[493]939        log(log_numbers, ExpProperties.logPref+"forams_log.txt");
940    log(log_energies,  ExpProperties.logPref+"energies_log.txt");
[422]941}
942
[380]943function log(tolog, fname)
944{
[430]945        var f = File.appendDirect(fname, "forams data");
[380]946        f.writeString("" + Simulator.stepNumber);
[401]947        for (var  i = 0; i < tolog.size; i++)
[380]948        {
949                f.writeString(";" + tolog[i]);
950        }
951        f.writeString("\n");
952        f.close();
953}
954
[567]955function createLogVector(cr, value)
956{
957        var vec = Vector.new();
958        for (var i = 0; i < species_genes.size; i++)
959        {
960                for (var j = 0; j < 2; j++)
961                {
962                        vec.add(0);
963                }
964                if (cr.data->lifeparams->species == i)
965                {
966                        vec[i*2+cr.data->lifeparams->gen] = value;             
967                }
968        }
969        return vec;
970}
971
972
[422]973// -------------------------------- step end --------------------------------
[479]974//TODO default params values in frams instead of microns/seconds
[380]975
[401]976@include "standard_events.inc"
[380]977
[401]978~
[380]979
[486]980property:
[444]981id:visualize
982name:Show reticulopodia and nutrients
[430]983type:d 0 1 0
[554]984group:
[430]985
[486]986property:
[434]987id:maxSteps
[554]988name:Maximum number of steps
[552]989type:d 0 10000000 0
[554]990group:
[432]991
[486]992property:
[567]993id:scalingFactor
994name:Scaling factor for micrometers
995type:f 0 -1 0.01
996group:
997
998property:
[554]999id:logging
1000name:Log statistics to file
1001type:d 0 1 0
1002group:
1003
1004property:
[493]1005id:logPref
1006name:Log prefix
1007type:s
1008
1009property:
[554]1010id:secPerStep
1011name:Seconds per simulation step
[568]1012help:~
[570]1013Number of seconds of foraminifera time per simulation step.
1014Lower values mean smoother animation.~
[554]1015type:f 1 480 300
1016flags: 16
1017group:
1018
1019property:
[474]1020id:foramSpeedMmPerMin
1021name:Speed of foraminfera in mm/min
[554]1022type:f 0.01 0.1 0.05
[474]1023flags: 16
1024group:Foraminifera
1025
[486]1026property:
[554]1027id:dir_change_sec
1028name:Number of seconds before direction change
1029type:d 300 300000 6000
[479]1030group:Foraminifera
1031
[486]1032property:
[554]1033id:foramPop
1034name:Initial forams population size
1035type:d 1 1000 20
[552]1036group:Foraminifera
1037
1038property:
[554]1039id:gametoPeriodSec
[479]1040name:Time of gametogenesis
[554]1041type:f 300 300000 21600
1042group:Reproduction
[479]1043
[486]1044property:
[554]1045id:gametSuccessRate
1046name:Ratio of successful gamets
1047type:f 0.0001 0.01 0.001
1048group:Reproduction
[479]1049
[486]1050property:
[554]1051id:divisionCost
1052name:Cost of division in pG
1053type:f 15 25 20
1054group:Reproduction
[474]1055
[486]1056property:
[554]1057id:min_repro_energ_haplo
[567]1058name:Min reproduction energy of haploid in pg
1059type:f 0 -1 350000
[554]1060group:Energy
[380]1061
[486]1062property:
[554]1063id:min_repro_energ_diplo
[567]1064name:Min reproduction energy of diploid in pg
1065type:f 0 -1 600000
[554]1066group:Energy
[479]1067
[486]1068property:
[554]1069id:repro_prob
1070name:Probability of reproduction
1071type:f 0 1 0.8
1072group:Reproduction
[380]1073
[486]1074property:
[554]1075id:energies0_haplo
1076name:Energy of offspring from diploid forams
1077type:f 0 -1 20
1078group:Energy
[479]1079
[486]1080property:
[554]1081id:energies0_diplo
1082name:Energy of offspring from diploid forams
1083type:f 0 -1 1.25
1084group:Energy
1085
1086property:
[567]1087id:max_chamber_num_haplo
1088name:Maximum number of haploid chambers
1089type:f 1 50 35
1090group:Energy
1091
1092property:
1093id:max_chamber_num_diplo
1094name:Maximum number of diploid chambers
1095type:f 1 50 35
1096group:Energy
1097
1098property:
[554]1099id:crossprob
1100name:Crossover probability
1101type:f 0 1 0
1102group:Reproduction
1103
1104property:
1105id:mutationprob
1106name:Mutation probability
1107type:f 0 1 0
1108group:Reproduction
1109
1110property:
1111id:reproTimeSec
1112name:Time before reproduction
1113type:d 0 10000 720
1114group:Reproduction
1115
1116property:
1117id:chamberGrowthSec
1118name:Time of the chamber growth in seconds
[567]1119type:f 720 43200 43200
[479]1120group:Foraminifera
1121
[486]1122property:
[422]1123id:chamber_proculus_haplo
[423]1124name:Size of proculus
[422]1125type:f
[421]1126group:Foraminifera
[380]1127
[486]1128property:
[422]1129id:chamber_proculus_diplo
[423]1130name:Size of proculus
[422]1131type:f
[380]1132group:Foraminifera
1133
[486]1134property:
[422]1135id:hunted_prob
1136name:Probability of being hunted
1137type:f 0 1 0
[554]1138group:Foraminifera
[380]1139
[486]1140property:
[557]1141id:zone1_range
[556]1142name:Zone 1 range in frams units
[554]1143type:f 0 200 10
[422]1144group:Foraminifera
[380]1145
[486]1146property:
[422]1147id:zone2_range
[556]1148name:Zone 2 range in frams units
[554]1149type:f 0 3000 30
[421]1150group:Foraminifera
[380]1151
[486]1152property:
[554]1153id:chamberCostPerSec
1154name:Cost of growning chamber per second
1155type:f 0 1 0.000001
1156group:Energy
[380]1157
[486]1158property:
[475]1159id:e_death_level_haplo
1160name:Minimal level of energy to sustain life of haploid
[554]1161type:f 0 1 0.5
1162group:Energy
[475]1163
[486]1164property:
[475]1165id:e_death_level_diplo
1166name:Minimal level of energy to sustain life of diploid
[554]1167type:f 0 1 0.5
1168group:Energy
[475]1169
[486]1170property:
[422]1171id:energy_hib
1172name:Energy used for hibernation during one step
[554]1173type:f 0 1 0.0000001
1174group:Energy
[422]1175
[486]1176property:
[422]1177id:energy_move
1178name:Energy used for movement during one step
[554]1179type:f 0 1 0.0000005
1180group:Energy
[422]1181
[486]1182property:
[380]1183id:e_meta
1184name:Idle metabolism
[554]1185type:f 0 1 0.0000005
[380]1186group:Energy
[556]1187help:Foraminifera consumes this proportion of its energy in one time step
[380]1188
[486]1189property:
[554]1190id:ingestion
1191name:Ingestion rate
1192type:f 0 -1 0.25
1193group:Energy
1194
1195property:
[493]1196id:nutrient_pop
[554]1197name:Nutrient population
[474]1198type:f 0 1000000
[380]1199group:Energy
1200help:How fast energy is created in the world
1201
[486]1202property:
[554]1203id:energy_nut
1204name:Nutrient energy
1205type:f 0 10000000
[481]1206group:Energy
1207
[486]1208property:
[554]1209id:nutrientradius
1210name:Nutrient size
1211type:f 0.001 0.9 0.1
[479]1212group:Energy
1213
[486]1214property:
[554]1215id:picoCarbonPerMikro
[556]1216name:Picograms of carbon in cubic micrometer
[554]1217type:f 0 -1 0.13
[380]1218group:Energy
1219
[486]1220property:
[380]1221id:feedtrans
[479]1222name:Energy transfer per second
[554]1223type:f 0 1 0.001
[380]1224group:Energy
[422]1225
[486]1226property:
[590]1227id:foodflux
1228name:POM flux in grams per second per square meter
1229type:f 0 1 0.0000000075631
[422]1230group:Energy
1231
[486]1232property:
[590]1233id:foodfluxChange
[554]1234name:Set variable feed rate
1235type:f 0 -1 0
[421]1236group:Energy
1237
[486]1238property:
[422]1239id:stress
1240name:Environmental stress
1241type:d 0 1 1
[554]1242group:
[422]1243
[486]1244property:
[422]1245id:repro_trigger
1246name:Reproduction trigger
1247type:d 0 1 1
[554]1248group:Reproduction
[422]1249
[486]1250property:
[422]1251id:creath
1252name:Creation height
[554]1253type:f -1 50 -0.99
[422]1254help:~
1255Vertical position (above the surface) where new Forams are revived.
1256Negative values are only used in the water area:
1257  0   = at the surface
1258-0.5 = half depth
1259-1   = just above the bottom~
1260
[554]1261property:
1262id:autorestart
1263name:Restart after extinction
1264help:Restart automatically this experiment after the last creature has died?
1265type:d 0 1 0
1266
[421]1267state:
1268id:nutrient
[428]1269name:Nutrient locations
[421]1270help:vector of vectors [x,y,energy]
1271type:x
1272flags:32
1273
[380]1274state:
1275id:notes
1276name:Notes
1277type:s 1
1278help:~
1279You can write anything here
1280(it will be saved to the experiment file)~
1281
1282state:
1283id:totaltestedcr
[421]1284name:Evaluated Forams
1285help:Total number of the Forams evaluated in the experiment
[380]1286type:d
1287flags:16
Note: See TracBrowser for help on using the repository browser.