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

Last change on this file since 1100 was 1100, checked in by Maciej Komosinski, 3 years ago

Cosmetic / minor fixes

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