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

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

Rotation of creatures in z axis changed to random. LocalDrive? usage replaced by drive.

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