function create_genotype(proculus_size, number_of_chambers, rgbstring) { const shift=0.7; const angle_delta=0.8; const angle_delta_delta=-0.015; const growing=1.05; var str="//0\n"; var size=proculus_size; for(var i=0;i0) str+="j:%d,%d,sh=1,dx=%g,ry=%g\n" % (i-1) % i % (size*shift) % (angle_delta+i*angle_delta_delta); size*=growing; } return str; } function init_chambers() { colors = ["1.0,1.0,0.0","1.0,0.5,0.0"]; retColors = ["1.0,1.0,1.0", "1.0,1.0,0.0"]; chambers = [ ["p:sh=1, sx=0.2, sy=0.2, sz=0.2, rz=3.14159265358979,", "p:0.18421219587326, 0.13, sh=1, sx=0.21, sy=0.21, sz=0.21,", "p:0.323935478925705, 0.195192575454712, -0.0246672090142965, sh=1, sx=0.2205, sy=0.2205, sz=0.2205,", "p:0.467822402715683, 0.258204102516174, -0.0246672090142965, sh=1, sx=0.231525, sy=0.231525, sz=0.231525,", "p:0.664101362228394, 0.309014827013016, -0.0246672090142965, sh=1, sx=0.24310125, sy=0.24310125, sz=0.24310125,", "p:0.860512733459473, 0.274790525436401, -0.0246672090142965, sh=1, sx=0.2552563125, sy=0.2552563125, sz=0.2552563125,", "p:1.0273220539093, 0.1655353307724, -0.0246672090142965, sh=1, sx=0.268019128125, sy=0.268019128125, sz=0.268019128125,", "p:1.13825333118439, -0.000509921927005053, -0.0246672090142965, sh=1, sx=0.28142008453125, sy=0.28142008453125, sz=0.28142008453125,", "p:1.17569863796234, -0.196833491325378, -0.0246672090142965, sh=1, sx=0.295491088757813, sy=0.295491088757813, sz=0.295491088757813,", "p:1.13369226455688, -0.392314255237579, -0.0246672090142965, sh=1, sx=0.310265643195703, sy=0.310265643195703, sz=0.310265643195703,"], ["p:sh=1, sx=0.1, sy=0.1, sz=0.1, rz=3.14159265358979,", "p:0.110527315735817, -0.0167302016913891, sh=1, sx=0.105, sy=0.105, sz=0.105, rx=3.63519277003091e-33,", "p:0.207026958465576, -0.080698736011982, 1.17627548103266e-17, sh=1, sx=0.11025, sy=0.11025, sz=0.11025,", "p:0.271191358566284, -0.169948443770409, 1.17627548103266e-17, sh=1, sx=0.1157625, sy=0.1157625, sz=0.1157625,", "p:0.291628688573837, -0.286643952131271, 1.17627548103266e-17, sh=1, sx=0.121550625, sy=0.121550625, sz=0.121550625,", "p:0.264833927154541, -0.403534322977066, 1.17627548103266e-17, sh=1, sx=0.12762815625, sy=0.12762815625, sz=0.12762815625,", "p:0.194418027997017, -0.500668346881866, 1.17627548103266e-17, sh=1, sx=0.1340095640625, sy=0.1340095640625, sz=0.1340095640625,", "p:0.091719962656498, -0.562735974788666, 1.17627548103266e-17, sh=1, sx=0.140710042265625, sy=0.140710042265625, sz=0.140710042265625,", "p:-0.0270438715815544, -0.57991486787796, 1.17627548103266e-17, sh=1, sx=0.147745544378906, sy=0.147745544378906, sz=0.147745544378906,", "p:-0.143122747540474, -0.549489378929138, 1.17627548103266e-17, sh=1, sx=0.155132821597852, sy=0.155132821597852, sz=0.155132821597852,"]]; } function createForamMorphology(morphotype, gen, chamber_num) { var geno = "//0\nm:Vstyle=foram\n" + chambers[morphotype][0] + "vr=" + colors[gen]; chamber_num = Math.min(chamber_num, chambers[morphotype].size - 1); for (var i = 0; i < chamber_num; i++) { geno += "\n" + chambers[morphotype][i+1] + "vr=" + colors[gen]; } for (var i = 0; i < chamber_num; i++) { geno += "\n" + "j:"+ i +", "+ (i+1) +", sh=1"; } return geno; } function setGenotype(mode) { if (mode->opt == "growth") { mode->cr.data->genes = mode->parent_genes; mode->cr.data->lifeparams = mode->parent_lifeparams; } else if (mode->opt == "birth") { mode->cr.data->genes = String.deserialize(String.serialize(mode->genes)); mode->cr.data->lifeparams = {"max_energy_level" : mode->energy0, "gen" : mode->gen, "hibernated" : 0, "species" : mode->species, "reproduce" : 0, "dir" : randomDir(), "dir_counter" : Math.random(int(secToSimSteps(ExpProperties.dir_change_sec))), "chamber_growth" : -1, "division_time" : -1}; } } function gametsDivision(parent_energy, energy0) { var number = 1; var result = parent_energy; while ((result-ExpProperties.divisionCost) >= energy0) { result = (result-ExpProperties.divisionCost)/2; number *= 2; } //Simulator.print("parent: " + parent_energy + " result: " + result + " number " + number); return {"energy" : result, "number" : number}; } function getEnergy0(radius) { return energyFromVolume(micronsToFrams(radius),1); } function reproduce_haploid(parent, parent2, clone) { var number, energy0, new_genes, gen; if (clone == 1) { var offspring = gametsDivision(parent.energy,getEnergy0(getGene(parent,"energies0",0)[0])); energy0 = offspring->energy; number = offspring->number; new_genes = parent.data->genes; parent.data->lifeparams->gen = 1 - parent.data->lifeparams->gen; //because of reversal of "gen" in createOffspring function gen = parent.data->lifeparams->gen; } else { var offspring1 = gametsDivision(parent.energy,getEnergy0(getGene(parent,"energies0", 0)[1])); var offspring2 = gametsDivision(parent2.energy,getEnergy0(getGene(parent2,"energies0", 0)[1])); energy0 = (offspring1->energy+offspring2->energy); number = ExpProperties.gametSuccessRate*(offspring1->number+offspring2->number)/2; new_genes = [parent.data->genes, parent2.data->genes]; gen = 1 - parent.data->lifeparams->gen; if (ExpProperties.logging == 1) { log(createLogVector(parent, parent.energy),ExpProperties.logPref+"repro_energies_log.txt"); log(createLogVector(parent2, parent2.energy),ExpProperties.logPref+"repro_energies_log.txt"); log(createLogVector(parent, number),ExpProperties.logPref+"repro_num_log.txt"); log(createLogVector(parent, parent.lifespan),ExpProperties.logPref+"lifespan_log.txt"); log(createLogVector(parent2, parent2.lifespan),ExpProperties.logPref+"lifespan_log.txt"); } } Simulator.print("haploid number of offspring: " + number + " energ0: " + energy0); for (var j = 0; j < number; j++) { createOffspring(createForamMorphology(gen, gen, 0), energy0, new_genes, parent.data->lifeparams); } } function reproduce_diploid(parent) { var offspring = gametsDivision(parent.energy,getEnergy0(getGene(parent,"energies0", 0)[0])); var energy0 = offspring->energy; var number = offspring->number; if (ExpProperties.logging == 1) { log(createLogVector(parent, parent.energy),ExpProperties.logPref+"repro_energies_log.txt"); log(createLogVector(parent, number),ExpProperties.logPref+"repro_num_log.txt"); log(createLogVector(parent, parent.lifespan),ExpProperties.logPref+"lifespan_log.txt"); } Simulator.print("diploid number of offspring: " + number+ " energ0: " + energy0); for (var j = 0; j < number / 2; j++) { var crossed = 0; //crossover if (Math.rnd01 < ExpProperties.crossprob) { crossover(parent, "min_repro_energies"); crossed = 1; } for (var k = 0; k < 2; k++) { createOffspring(createForamMorphology(1 - parent.data->lifeparams->gen, 1 - parent.data->lifeparams->gen, 0), energy0, parent.data->genes[0], parent.data->lifeparams); } //reverse of crossover for fossilization if (crossed == 1) { crossover(parent, "min_repro_energies"); crossed = 0; } } } function reproduce_parents(species) { var parent1 = null; var parent2 = null; var pop = Populations[0]; for (var i = pop.size-1; i >= 0; i--) { if (pop[i].data->lifeparams->reproduce == 1 && pop[i].data->lifeparams->species == species) { if ((pop[i].data->lifeparams->gen==1) || ((pop[i].data->lifeparams->gen==0) && ExpProperties.stress == 0)) { continue; } else if (parent1 == null) { parent1 = pop[i]; } else if (parent2 == null) { parent2 = pop[i]; } if (parent1 != null && parent2 != null) { //when parents are ready for reproduction start gametogenesis if (parent1.data->lifeparams->division_time == -1 && parent2.data->lifeparams->division_time == -1) { var time = int(secToSimSteps(ExpProperties.gametoPeriodSec)); parent1.data->lifeparams->division_time = time; parent2.data->lifeparams->division_time = time; parent1.idleen = 0; parent2.idleen = 0; //Simulator.print("parents "+parent1.uid + " " + parent2.uid + " ready to repro: "+Simulator.stepNumber); } //when gametogenesis is finished fuse gamets else if (parent1.data->lifeparams->division_time == 0 && parent2.data->lifeparams->division_time == 0) { reproduce_haploid(parent1, parent2, 0); print_repro_info(parent1); print_repro_info(parent2); pop.kill(parent1); pop.kill(parent2); parent1 = null; parent2 = null; } } } } } function readyToRepro(cr) { var reproduced = 1; if (cr.data->lifeparams->gen == 1) { reproduce_diploid(cr); } else if (ExpProperties.stress == 0) { reproduce_haploid(cr, null, 1); } else { if (cr.signals.size == 0) { cr.signals.add("repro"+cr.data->lifeparams->species); cr.signals[0].power = 1; } reproduced = 0; cr.data->lifeparams->reproduce = 1; } if (reproduced == 1) { print_repro_info(cr); Populations[0].kill(cr); } return reproduced; } function print_repro_info(cr) { Simulator.print("Reproduced " + cr.data->lifeparams->gen + " of species " + cr.data->lifeparams->species + " energy: " + cr.energy); } function foramReproduce(cr) { var properEnergy = cr.energy >= energyFromVolume(max_chamber_volume[cr.data->lifeparams->gen][getGene(cr, "min_repro_energies",0)[cr.data->lifeparams->gen]],0); var reproduced = 0; //if creature has proper energy if ( properEnergy && cr.signals.size == 0) { //reproduce with probability repro_prob if (Math.rnd01 <= ExpProperties.repro_prob) //TODO env trigger { reproduced = readyToRepro(cr); } else if (cr.signals.receive("repro"+cr.data->lifeparams->species) > 0) { reproduced = readyToRepro(cr); } if (reproduced == 1) return 1; } else if (!properEnergy) { cr.signals.clear(); cr.data->lifeparams->reproduce = 0; } return 0; } function crossover(parent, gene) { var tmp = parent.data->genes[0][gene]; parent.data->genes[0][gene] = parent.data->genes[1][gene]; parent.data->genes[1][gene] = tmp; } function createOffspring(geno, energy, parent_genes, parent_lifeparams) { curColor = retColors[1-parent_lifeparams->gen]; var cr = Populations[0].add(geno); cr.energy0 = energy; cr.energy = cr.energy0; setGenotype({"opt" : "birth", "cr" : cr, "gen" : 1 - parent_lifeparams->gen, "species" : parent_lifeparams->species, "energy0" : cr.energy0, "genes" : parent_genes}); placeRandomlyNotColliding(cr); }