expdef: name:Foraminifera simulation info:~ Genes and parameter values which control reproduction are stored in user1 and user2 fields. user1: genes which are not encoded in ff genotype: Vamin - Minimum stored energy necessary for reproduction amin - minimal age for reproduction user2: Physiological parameters of foraminifera: Va - amount of the stored energy gen - generation: 0 haploid, 1 diploid ~ code:~ global foodenergywaiting; global reprocounter; // -------------------------------- experiment begin -------------------------------- function onExpDefLoad() { // define genotype and creature groups GenePools.clear(); Populations.clear(); GenePools[0].name = "Unused"; var pop = Populations[0]; pop.name = "Creatures"; pop.en_assim = 0; pop.nnsim = 1; pop.enableperf = 1; pop.death = 1; pop.energy = 1; pop.selfmask = 0x10001; pop.othermask = 0x30000; pop.perfperiod = 25; pop = Populations.addGroup("Food"); pop.nnsim = 0; pop.enableperf = 0; pop.death = 1; pop.energy = 1; pop.selfmask = 0x20002; pop.othermask = 0x30002; ExpParams.genh = "/*F*/1,1.1,1.1,1.1,1,1,1"; ExpParams.gend = "/*F*/1,1,1,1,1,1,1"; ExpParams.p_mut = 50; ExpParams.e_meta = 0.1; ExpParams.feedrate = 0.7; ExpParams.feede0 = 100; ExpParams.feedtrans = 3; ExpParams.creath = -0.99; //just above the bottom ExpParams.foodgen = "//0\np:sh=1,sx=0.1,sy=0.1,sz=0.1"; ExpParams.autorestart = 0; ExpParams.psize = 10; ExpParams.ofnumh = 14; ExpParams.ofnumd = 4; ExpParams.v_min_d = 200; ExpParams.v_min_h = 500; ExpParams.age_min_d = 150; ExpParams.age_min_h = 300; ExpParams.crossprob = 0.3; ExpParams.repro_time = 200; ExpParams.repro_thr = 1; ExpState.totaltestedcr = 0; ExpState.food = ""; foodenergywaiting = ExpParams.feede0; reprocounter = 0; ExpParams.wsize = 30; World.wrldwat = 50; World.wrldsiz = ExpParams.wsize; World.wrldbnd = 1; } @include "standard_placement.inc" function onExpInit() { Populations[0].clear(); Populations[1].clear(); for (var i = 0; i < ExpParams.psize; i++) { var cr = Populations[0].add(ExpParams.genh); cr.name = "Initial creature" + i; placeCreatureRandomly(cr, 0, 0); cr.energ0 = ExpParams.v_min_h - ExpParams.repro_thr; cr.energy = cr.energ0; cr.user1 = {"vamin" : ExpParams.v_min_h, "amin": ExpParams.age_min_h}; cr.user2 = {"Va" : ExpParams.v_min_h - ExpParams.repro_thr, "gen" : 0 }; } ExpState.totaltestedcr = 0; foodenergywaiting = ExpParams.feede0; } function onExpLoad() { for (var pop in Populations) pop.clear(); Loader.addClass(sim_params.*); Loader.setBreakLabel(Loader.BeforeUnknown, "onExpLoad_Unknown"); Loader.run(); Simulator.print("Loaded " + Populations[0].size + " creatures and " + Populations[1].size + " food objects"); } function onExpLoad_Unknown() { if (Loader.objectName == "org") // saved by the old expdef { var g = Genotype.newFromString(""); Loader.currentObject = g; Interface.makeFrom(g).setAllDefault(); Loader.loadObject(); var cr = Populations[0].add(g); if (cr != null) { cr.rotate(0, 0, Math.rnd01*Math.twopi); if ((typeof(g.user1) == "Vector") && (g.user1.size >= 3)) { // [x,y,energy] cr.move(g.user1[0] - cr.center_x, g.user1[1] - cr.center_y, 0); cr.energy = g.user1[2]; } else { cr.move(Math.rnd01*World.wrldsiz - cr.center_x, Math.rnd01*World.wrldsiz - cr.center_y, 0); } } } else if (Loader.objectName == "Creature") { Loader.currentObject = CreatureSnapshot.new(); Loader.loadObject(); Populations[0].add(Loader.currentObject); } } function onExpSave() { File.writeComment("saved by '%s.expdef'" % Simulator.expdef); var i, tmpvec = []; for (var cr in Populations[1]) tmpvec.add([cr.center_x, cr.center_y, cr.energy]); ExpState.food = tmpvec; File.writeObject(sim_params.*); ExpState.food = null; //vectors are only created for saving and then discarded for (var cr in Populations[0]) File.writeObject(cr); } // -------------------------------- experiment end -------------------------------- // -------------------------------- creature begin -------------------------------- function onCreaturesBorn(cr) { cr.idleen = ExpParams.e_meta; } function readyToRepro(cr) { cr.signals.add("repro"); cr.signals.get(0).power = 1; } function onCreaturesStep(cr) { cr.moveAbs(cr.pos_x, cr.pos_y, 0); var p = cr.getMechPart(0); var n = cr.signals.receiveSet("food", ExpParams.food_range); if (n.size > 0) { var i; var mp; var distvec = XYZ.new(0, 0, 0); var dist; var mindist = 100000000000; var mindistvec = null; if (Math.rnd01 < 0.8) { for (i = 0;i < n.size;i++) { mp = n[i].value; distvec.set(mp.pos); distvec.sub(p.pos); dist = distvec.length; if (dist < mindist) { mindist = dist; mindistvec = distvec.clone(); } } } else { mp = n[Math.random(n.size)].value; distvec.set(mp.pos); distvec.sub(p.pos); mindistvec = distvec.clone(); } mindistvec.normalize(); mindistvec.scale( -0.1); cr.localDrive = mindistvec; } else { cr.localDrive = (0.1, 0, 0); } var properAge = cr.user2["Va"] >= cr.user1["vamin"]; var properSize = cr.user1["amin"] <= cr.lifespan; //if creature has proper age and cytoplasm amount if ( properAge && properSize ) { //reproduce with probability repro_prob if (Math.rnd01 <= ExpParams.repro_prob) { readyToRepro(cr); } } if ( properAge && properSize && (cr.signals.receive("repro") > 0)) { readyToRepro(cr); } } function onCreaturesDied(cr) { //fossilization var geno = GenePools[0].add(cr.genotype); geno.user1 = cr.user1; geno.user2 = cr.user2; Simulator.print("\"" + cr.name + "\" died..."); ExpState.totaltestedcr++; } // -------------------------------- creature end -------------------------------- // -------------------------------- food begin -------------------------------- function onFoodStep(cr) { cr.moveAbs(cr.pos_x % ExpParams.wsize, cr.pos_y % ExpParams.wsize, 0.5); } function addfood() { var cr = Populations[1].add(ExpParams.foodgen); cr.name = "Food"; cr.idleen = 0; cr.energ0 = ExpParams.feede0; cr.energy = cr.energ0; cr.signals.add("food"); cr.signals.get(0).value = cr.getMechPart(0); var retry = 50; //try 50 times while (retry--) { placeCreatureRandomly(cr, 0, 0); cr.signals.get(0).value = cr.getMechPart(0); if (!cr.boundingBoxCollisions(0)) return cr; } return cr; } function onFoodCollision() { if (Collision.Creature2.user2 != null) { var e = Collision.Part2.ing * ExpParams.feedtrans; //Simulator.print("transferring "+e+" from "+Collision.Creature1.name+" to "+Collision.Creature2.name+" ("+Collision.Creature2.energy+")"); Collision.Creature1.energy_m = Collision.Creature1.energy_m + e; Collision.Creature2.energy_p = Collision.Creature2.energy_p + e; var ener = float(Collision.Creature2.user2.get("Va")); var sum = float(float(ener) + float(e)); Collision.Creature2.user2.set("Va", float(sum)); } } // -------------------------------- food end -------------------------------- // -------------------------------- step begin -------------------------------- function reproduce(repro_list, number) { for (var i = 0; i < repro_list.size; i++) { var parent = Populations[0].get(repro_list[i]); var energ = parent.user2["Va"] / number; for (var j = 0; j < number; j++) { var cr = Populations[0].add(ExpParams.gend); cr.energ0 = energ; cr.energy = cr.energ0; if (parent.user2["gen"] == 0) { cr.user1 = {"vamin" : ExpParams.v_min_d, "amin": ExpParams.age_min_d}; } else { cr.user1 = {"vamin" : ExpParams.v_min_h, "amin": ExpParams.age_min_h}; } cr.user2 = { "Va" : cr.energ0, "gen" : 1 - parent.user2["gen"] }; placeCreatureRandomly(cr, 0, 0); } } for (var j = 0; j < repro_list.size; j++) { Populations[0].kill(repro_list[j]); } } function log(tolog, fname) { var f = File.appendDirect(fname, "description"); f.writeString("" + Simulator.stepNumber); for (var i = 0; i < tolog.size; i++) { f.writeString(";" + tolog[i]); } f.writeString("\n"); f.close(); } function onStep() { var haploids = 0; var diploids = 0; var e_inc_h = 0.0; var e_inc_d = 0.0; var e_nut = 0.0; for (var i = 0; i < Populations[0].size; i++) { var cr = Populations[0].get(i); if (cr.user2["gen"] == 0) { haploids += 1; e_inc_h += cr.energy; } else { diploids += 1; e_inc_d += cr.energy; } } for (var i = 0; i < Populations[1].size; i++) { var cr = Populations[1].get(i); e_nut += cr.energy; } if (haploids < 2 && diploids == 0) { Simulator.print("no more creatures, stopped."); Simulator.stop(); } var l1 = Vector.new(); l1 = [haploids, diploids, Populations[1].size]; var l2 = Vector.new(); l2 = [e_inc_h, e_inc_d, e_nut]; log(l1, "log.txt"); log(l2, "log2.txt"); //food growth --------------------------------------------- foodenergywaiting = foodenergywaiting + ExpParams.feedrate; if (foodenergywaiting > ExpParams.feede0) { for (var i = 0; i < ExpParams.foodPop; i++) { addfood(); } foodenergywaiting = 0.0; Simulator.checkpoint(); } //reproduction -------------------------------------------- reprocounter += 1; if (reprocounter > ExpParams.repro_time) { reprocounter = 0; var to_repro_h = Vector.new(); var to_repro_d = Vector.new(); for (var i = 0; i < Populations[0].size; i++) { var cr = Populations[0].get(i); if (cr.signals.size > 0) { if (cr.user2["gen"] == 0) { to_repro_h.add(i); } else { to_repro_d.add(i); } } } if (to_repro_h.size > 0) { reproduce(to_repro_h, ExpParams.ofnumh); } if (to_repro_d.size > 1) { reproduce(to_repro_d, ExpParams.ofnumd); } } //check for death ----------------------------------------------- if (Populations[0].size == 0) { if (ExpParams.autorestart) { Simulator.print("no more creatures, restarting..."); onExpInit(); } else { Simulator.print("no more creatures, stopped."); Simulator.stop(); } } } // -------------------------------- step end -------------------------------- @include "standard_events.inc" ~ prop: id:wsize name:world size type:d 10 1000 20 prop: id:foodPop name:food size type:d 1 1000 10 prop: id:age_min name:minimal age for reproduction type:d 100 10000 200 prop: id:age_min_h name:Min reproduction age of haploid forams type:d 100 10000 300 group:Foraminifera prop: id:age_min_d name:Min reproduction age of diploid forams type:d 100 10000 200 group:Foraminifera prop: id:v_min_h name:Min reproduction energy of haploid forams type:d 100 10000 300 group:Foraminifera prop: id:v_min_d name:Min reproduction energy of diploid forams type:d 100 10000 150 group:Foraminifera prop: id:repro_thr name:treshold for reproduction type:d 1 1000 1 prop: id:food_range name:range of food smell type:d 0 10000 10000 prop: id:repro_time name:time before reproduction type:d 0 1000 prop: id:psize name:initial population size type:d 1 1000 100 prop: id:ofnumh name:Number of offspring from haploid forams type:d group:Foraminifera prop: id:ofnumd name:Number of offspring from diploid forams type:d group:Foraminifera prop: id:repro_prob name:probability of reproduction type:f 0 1 0.9 prop: id:crossprob name:crossover probability type:f 0 1 prop: id:genh name:Initial genotype of haploid forams type:s 1 group:Foraminifera prop: id:gend name:Initial genotype of diploid forams type:s 1 group:Foraminifera prop: id:creath name:Creation height type:f -1 50 help:~ Vertical position (above the surface) where new creatures are revived. Negative values are only used in the water area: 0 = at the surface -0.5 = half depth -1 = just above the bottom~ prop: id:p_mut name:Mutations type:f 0 100 prop: id:e_meta name:Idle metabolism type:f 0 1 group:Energy help:Each stick consumes this amount of energy in one time step prop: id:feedrate name:Feeding rate type:f 0 100 group:Energy help:How fast energy is created in the world prop: id:feede0 name:Food's energy group:Energy type:f 0 1000 prop: id:feedtrans name:Ingestion multiplier group:Energy type:f 0 100 prop: id:foodgen name:Food's genotype group:Energy type:s 1 prop: id:autorestart name:Restart after extinction group: help:Restart automatically this experiment after the last creature has died? type:d 0 1 state: id:notes name:Notes type:s 1 help:~ You can write anything here (it will be saved to the experiment file)~ state: id:totaltestedcr name:Evaluated creatures help:Total number of the creatures evaluated in the experiment type:d flags:16 state: id:food name:Food locations help:vector of vectors [x,y,energy] type:x flags:32