Index: /experiments/frams/foraminifera/data/scripts/foraminifera.expdef
===================================================================
--- /experiments/frams/foraminifera/data/scripts/foraminifera.expdef	(revision 421)
+++ /experiments/frams/foraminifera/data/scripts/foraminifera.expdef	(revision 422)
@@ -6,11 +6,14 @@
 user1:
 genes which are not encoded in Ff genotype:
-minenergy - Minimum stored energy necessary for reproduction
-minage - minimal age for reproduction
+min_repro_energy - Minimum energy necessary for reproduction
+hibernation - Defines foram behavior in the case of no nutrients
 
 user2:
 Physiological parameters of foraminifera:
-Va - amount of the stored energy
+max_energy_level - maximum energy level reached so far
 gen - generation: 0 haploid, 1 diploid
+species - species: 0 not hibernating 1 hibernating
+hibernated - 0/1 foram isn't/is hibernated
+reproduce - 0/1 foram isn't/is ready for reproduction 
 ~
 code:~
@@ -28,4 +31,9 @@
 global nutrientenergywaiting;
 global reprocounter;
+global colors;
+global chambers;
+global o;
+global max_chamber_energ;
+
 
 @include "foraminifera.inc"
@@ -39,6 +47,4 @@
 	Populations.clear();
 	GenePools[0].name = "Unused";
-
-	SignalView.mode = 1;
 
 	var pop = Populations[0];
@@ -52,5 +58,5 @@
 	pop.othermask = 0x20001;
 	//pop.selfmask = 0x20002; pop.othermask = 0x10002;
-	pop.perfperiod = 25;
+	pop.perfperiod = 25; 
 
 	pop = Populations.addGroup("Nutrients");
@@ -61,49 +67,89 @@
 	pop.selfmask = 0x20002;
 	pop.othermask = 0x10000;
-
-	//radius of the chamber
-	ExpParams.rads = [1.2, 0.6];
-	//inital genotypes
-	ExpParams.genh = createForamGenotype(ExpParams.rads[0]);
-	ExpParams.gend = createForamGenotype(ExpParams.rads[1])+"\nn:p=0,d=\"S\"";
+	//pop.othermask = 0x10002;
+
+	//world
+	SignalView.mode = 1;
+	ExpParams.world_size = 100;
+	World.wrldwat = ExpParams.world_size;
+	World.wrldsiz = ExpParams.world_size;
+	World.wrldbnd = 1;
+	ExpParams.stress = 1;
 	ExpParams.creath = -0.99; //just above the bottom
-	ExpParams.e_meta = 0.1;
-	ExpParams.feedrate = 0.5;
-	ExpParams.feede0 = 100;
-	ExpParams.feedtrans = 3;
-	ExpParams.nutrientsize = 0.1;
-	ExpParams.nutrientgen = "//0\np:sh=2,sx="+ExpParams.nutrientsize+",sy="+ExpParams.nutrientsize+",sz="+ExpParams.nutrientsize+"\nn:d=T,p=0"; 
 	ExpParams.autorestart = 0;
-	ExpParams.popsize = 10;
+
 	//ExpParams.logging = 1; //uncomment to enable logging simulation parameters to log files
 
-	//number of offspring
-	ExpParams.energy0h = 40;
-	ExpParams.energy0d = 25;
-	//minial volume for reproduction
-	ExpParams.minenerg = [300, 300];
-	//minimal age for reproduction
-	ExpParams.minage = [100, 100];
-	//crossover probability
+	//reproduction
+	ExpParams.foramPop = 3;
 	ExpParams.crossprob = 0.4;
-	//mutation probability
 	ExpParams.mutationprob = 0.2;
-	ExpParams.repro_time = 45;
-
-	//grwoth speed in simulation steps
-	ExpParams.growth_step = 50;
-
+	ExpParams.repro_time = 20;
+	reprocounter = 0;
+
+	//morphology
+	init_chambers();
+	ExpParams.chamber_proculus_haplo = scale(60);
+	ExpParams.chamber_difference_haplo = 0.0;
+	ExpParams.chamber_proculus_diplo = scale(20);
+	ExpParams.chamber_difference_diplo = 0.2;
+	max_chamber_energ = [Vector.new(), Vector.new()];
+	for (var j = 0; j < 2; j++)
+	{
+		for (var i = 0; i < chambers[0].size; i++)
+		{
+			max_chamber_energ[j].add(((Math.pow(getProperty(j, "chamber_proculus"),3) + Math.pow(getProperty(j, "chamber_proculus") + (i) * getProperty(j, "chamber_difference"),3))*(i+1))/2);
+
+		}                                  
+	}
+	ExpParams.zone1_range = scale(250);
+	ExpParams.zone2_range = scale(5000);
+
+	//energetics
+	ExpParams.min_repro_energ_haplo = max_chamber_energ[0][2];
+	ExpParams.min_repro_energ_diplo = max_chamber_energ[1][8];
+	ExpParams.e_meta = 0.00003 * max_chamber_energ[0][0];
+	ExpParams.energy_hib = 0.00003 * max_chamber_energ[0][0];
+	ExpParams.energy_move = 0.0003 * max_chamber_energ[0][0];
+	ExpParams.energies0_haplo = max_chamber_energ[0][0] - 0.1*max_chamber_energ[0][0];
+	ExpParams.energies0_diplo = max_chamber_energ[1][0] - 0.1*max_chamber_energ[1][0];
+	ExpParams.feedtrans = 0.05;
+	ExpParams.e_repro_cost_haplo = 0.5; 
+	ExpParams.e_repro_cost_diplo = 0.3;
+
+	//nutrients
+	ExpParams.nutrientsize = scale(10);
+	ExpParams.energy_nut = 100 * Math.pow(ExpParams.nutrientsize, 3);
+	ExpParams.nutrientPop = 10;
+	ExpParams.feedrate = 0.0025;
+	nutrientenergywaiting = ExpParams.energy_nut;
 	ExpState.totaltestedcr = 0;
 	ExpState.nutrient = "";
-	nutrientenergywaiting = ExpParams.feede0;
-	reprocounter = 0;
-
-	ExpParams.worldsize = 50;
-	World.wrldwat = 50;
-	World.wrldsiz = ExpParams.worldsize;
-	World.wrldbnd = 1;
 }
 
 @include "standard_placement.inc"
+
+function scale(x)
+{
+	return x*0.025;
+}
+
+function getProperty(gen, prop_id)
+{
+	var ploid = "haplo";
+	if (gen == 1) ploid = "diplo";
+	return ExpParams.[prop_id + "_" + ploid];
+}
+
+function addInitialForam(species, i)
+{
+	var geno = createForamGenotype(0, species, 0);
+	var cr = Populations[0].add(geno);
+	cr.name = "Initial creature" + species + "_" + i;
+	placeCreatureRandomly(cr, 0, 0);
+	cr.energy0 = getProperty(0, "energies0");
+	cr.energy = cr.energy0;
+	setGenotype({"opt" : 0, "cr" : cr, "species" : species});
+}
 
 function onExpInit()
@@ -112,16 +158,12 @@
 	Populations[1].clear();
 
-	for (var i = 0; i < ExpParams.popsize; i++)
-	{
-		var cr = Populations[0].add(ExpParams.genh);
-		cr.name = "Initial creature" + i;
-		placeCreatureRandomly(cr, 0, 0);
-		cr.energy0 = ExpParams.energy0h;
-		cr.energy = cr.energy0;
-		cr.user1 = {"minenergy" : ExpParams.minenerg[0], "minage": ExpParams.minage[0]};
-		cr.user2 = {"Va" : ExpParams.energy0h, "gen" : 0, "growth_step" : ExpParams.growth_step, "rsize" : ExpParams.rads[0], "vinit" : ExpParams.energy0h};
-	}
+	for (var i = 0; i < ExpParams.foramPop; i++)
+	{
+		addInitialForam(0, i);	
+		addInitialForam(1, i);
+	}
+	o = Populations[0][0].getMechPart(0).orient.clone();
 	ExpState.totaltestedcr = 0;
-	nutrientenergywaiting = ExpParams.feede0;
+	nutrientenergywaiting = ExpParams.energy_nut;
 }
 
@@ -191,9 +233,4 @@
 // -------------------------------- foram begin -----------------------------------
 
-function createForamGenotype(radius)
-{
-	return "//0\np:sh=1,sx=" + radius + ",sy=" + radius + ",sz=" + radius + ", rz=3.14159265358979";
-}
-
 function onForamsBorn(cr)
 {
@@ -214,22 +251,26 @@
 }
 
-function readyToRepro(cr)
-{
-	cr.signals.add("repro");
-	cr.signals[0].power = 1;
-}
-
-function foramMove(cr)
-{
-	//TODO moving inside sediment?
-	cr.moveAbs(cr.pos_x, cr.pos_y, 0); //adjustment in z axis
-
+function foramGrow(cr, chamber_num)
+{
+	var geno = createForamGenotype(cr.user2["gen"], cr.user2["species"], chamber_num);
+	var cr2 = Populations[0].add(geno);
+
+	cr2.energy0 = cr.energy;
+	cr2.energy = cr2.energy0;
+
+	setGenotype({"cr" : cr2, "parent_user1" : cr.user1, "parent_user2" : cr.user2, "opt" : 2});
+	cr2.moveAbs(cr.center_x - cr2.size_x / 2, cr.center_y - cr2.size_y / 2, cr.pos_z);
+
+	Populations[0].delete(cr);
+}
+
+function stepToNearest(cr, range)
+{
 	var p = cr.getMechPart(0);
-	var n = cr.signals.receiveSet("nutrient", ExpParams.nutrient_range);
+	var n = cr.signals.receiveSet("nutrient", ExpParams.zone2_range);
 
 	//if signals are received find the source of the nearest
 	if (n.size > 0)
 	{
-
 		var i;
 		var mp;
@@ -255,82 +296,119 @@
 		mindistvec.scale(-0.08);
 		cr.localDrive = mindistvec;
-	}
-
+		return 1;
+	}
+	
 	else
+		return 0;
+}
+
+function moveEnergyDec(cr)
+{
+	if (cr.user2["hibernated"] == 1)
+	{
+		cr.energy_m += ExpParams.energy_hib;
+	}
+	else
+	{
+		cr.energy_m += ExpParams.energy_move;
+	}
+}
+
+function foramMove(cr)
+{
+	//TODO moving inside sediment?
+
+	//adjustment in z axis
+	cr.moveAbs(cr.pos_x, cr.pos_y, 0.5);
+
+	//are there any nutrients in zone 1?
+	if (cr.boundingBoxCollisions() == 2)
+	{
+		if (cr.user2["hibernated"] == 1)
+			cr.user2["hibernated"] = 0;
+		return;	
+	}
+
+	else if (cr.user2["hibernated"] == 1)
+	{ 
+		moveEnergyDec(cr);
+		return;
+	}
+
+	//are there any nutrients in zone 2?
+	else
+	{
+		var moved = stepToNearest(ExpParams.zone2_range); //TODO weighted sum of distance and energy
+		if (moved==1)
+		{
+			moveEnergyDec(cr); 
+			return;
+		}
+	}
+
+	//no nutrients in zone 2
+
+	var hibernation = 0;
+	if (cr.user2["gen"] == 0) hibernation =  cr.user1["hibernation"];
+	else hibernation =  cr.user1[0]["hibernation"];
+	//hibernation
+	if (hibernation == 1)
+	{
+		moveEnergyDec(cr);
+		cr.user2["hibernated"] = 1;
+		cr.localDrive = XYZ.new(0,0,0);
+	}
+	//random move
+	else
 	{
 		cr.localDrive = (0.1 * Math.rnd01, 0.1 * Math.rnd01, 0);
-	}
-}
-
-function foramGrow(cr)
-{
-		//TODO how size is related to the energy?
-		cr.user2["rsize"] = ExpParams.rads[cr.user2["gen"]] * Math.min(Math.max(float(cr.user2["Va"] / cr.user2["vinit"]) * 0.5, 1.0), 2.5);
-		var geno = createForamGenotype(cr.user2["rsize"]);
-		if (cr.user2["gen"] == 1)
+		moveEnergyDec(cr);
+	}
+}
+
+function onForamsCollision()
+{
+	if (Collision.Creature1.user2 != null)
+	{
+		Collision.Creature1.localDrive = XYZ.new(0,0,0);
+		var e = Collision.Part2.ing * ExpParams.feedtrans; //TODO efficiency dependent on age
+		//Simulator.print("transferring "+e+" to "+Collision.Creature1.name+" from "+Collision.Creature2.name+" ("+Collision.Creature2.energy+")");
+		Collision.Creature2.energy_m = Collision.Creature2.energy_m + e;
+		Collision.Creature1.energy_p = Collision.Creature1.energy_p + e;
+		Collision.Creature1.user2["hibernated"] = 0;
+	}
+}
+
+function onForamsStep(cr)
+{
+	cr.getMechPart(0).orient.set(o);
+
+	if (deathConditions(cr) == 1)
+	{
+		Populations[0].kill(cr);
+		return;
+	}
+
+	foramMove(cr);
+
+	cr.user2["max_energy_level"] = Math.max(cr.energy, cr.user2["max_energy_level"]);
+	if  (cr.numparts <= chambers[0].size)
+	{
+		if ((cr.user2["max_energy_level"] >= max_chamber_energ[cr.user2["gen"]][cr.numparts-1])) 	
 		{
-			geno += "\nn:p=0,d=\"S\""; //TODO why initial genotypes are not used as defined in ExpParams?
-			//TODO maybe it would be nice if they rotated so the "S" would show where they are going (direction/intention)
-		}
-		var cr2 = Populations[0].add(geno);
-		cr2.energy0 = cr.energy;
-		cr2.energy = cr2.energy0;
-		setGenotype(cr2, cr.user1, cr.user2);
-		cr2.moveAbs(cr.center_x - cr2.size_x / 2, cr.center_y - cr2.size_y / 2, cr.pos_z);
-
-		Populations[0].delete(cr);
-}
-
-function onForamsStep(cr)
-{
-	foramMove(cr);
-
-	//energy costs depend on size
-	if (cr.energy > 100)
-	{
-		//TODO energy costs dependent on size
-		// cr.energy_m = cr.user2["Va"]/cr.user2["vinit"];
-	}
-
-	//TODO lifespan should not be used, it is set to 0 with every growth_step
-	if (cr.lifespan >= ExpParams.max_age)
-	{
-		//TODO what is max age value? should there be one
-		//Populations[0].kill(cr);
-		//return;
-	}
-
-	//foram growth
-	if (cr.lifespan == cr.user2["growth_step"])
-	{
-		foramGrow(cr);
-	}
+			foramGrow(cr, cr.numparts); 
+			return;
+		}	
+	}
+
+	foramReproduce(cr);	
+}
+
+function deathConditions(cr)
+{
+	if ((cr.energy <= ExpParams.e_death_level) || (Math.rnd01 < ExpParams.hunted_prob))
+		return 1;
 	else
-	{
-		var properSize = 0;
-
-		if (cr.user2["gen"] == 0)
-		{
-			properSize = cr.user2["Va"] >= cr.user1["minenergy"];
-		}
-		else
-		{
-			properSize = cr.user2["Va"] >= cr.user1[0]["minenergy"]; //TODO gene selection
-		}
-
-		//if creature has proper age and cytoplasm amount
-		if ( properSize )
-		{
-			//reproduce with probability repro_prob
-			if (Math.rnd01 <= ExpParams.repro_prob)
-			{
-				readyToRepro(cr);
-			}
-		}
-		if ( properSize && (cr.signals.receive("repro") > 0))
-		{
-			readyToRepro(cr);
-		}
-	}
+		return 0;
 }
 
@@ -345,34 +423,25 @@
 }
 
-function setGenotype(cr, new_user1, new_user2)
-{
-	cr.user2 = {"Va" : new_user2["Va"], "gen" : new_user2["gen"], "growth_step" : new_user2["growth_step"], "rsize" : new_user2["rsize"], "vinit": new_user2["vinit"]};
-	if (cr.user2["gen"] == 0)
-	{
-		cr.user1 = {"minenergy" : new_user1["minenergy"], "minage": new_user1["minage"] };
-	}
-	else if (cr.user2["gen"] == 1)
-	{
-		cr.user1 = [ {"minenergy" : new_user1[0]["minenergy"], "minage": new_user1[0]["minage"] }, {"minenergy" : new_user1[1]["minenergy"], "minage": new_user1[1]["minage"] }];
-	}
-
-}
-
 // --------------------------------foram end -------------------------------------
 
 // -------------------------------- nutrient begin --------------------------------
 
+function createNutrientGenotype(nutrientsize, zone1_range)
+{
+	return "//0\np:sh=3,sx="+nutrientsize+",sy="+(zone1_range + nutrientsize)+",sz="+(zone1_range+nutrientsize)+",ry=1.5,vr=0.0,1.0,0.0"; 
+}
+
 function onNutrientsStep(cr)
 {
-	cr.moveAbs(cr.pos_x % ExpParams.worldsize, cr.pos_y % ExpParams.worldsize, 0.5);
+	cr.moveAbs(cr.pos_x % ExpParams.world_size, cr.pos_y % ExpParams.world_size, -ExpParams.zone1_range+0.5);
 }
 
 function addNutrient()
 {
-	var cr = Populations[1].add(ExpParams.nutrientgen);
+	var cr = Populations[1].add(createNutrientGenotype(ExpParams.nutrientsize, ExpParams.zone1_range));
 
 	cr.name = "Nutrients";
 	cr.idleen = 0;
-	cr.energy0 = ExpParams.feede0;
+	cr.energy0 = ExpParams.energy_nut;
 	cr.energy = cr.energy0;
 	cr.signals.add("nutrient");
@@ -380,16 +449,19 @@
 	cr.signals[0].value = cr.getMechPart(0);
 
-	placeRandomlyNotColliding(cr);
-}
-
-function onNutrientsCollision()
-{
-	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;
-		Collision.Creature2.user2["Va"] = float(Collision.Creature2.user2["Va"]) + float(e);
+	placeCreatureRandomly(cr, 0, 0);
+}
+
+function nutrientGrowth()
+{
+	nutrientenergywaiting = nutrientenergywaiting + ExpParams.feedrate;
+	if (nutrientenergywaiting > ExpParams.energy_nut)
+	{
+		for (var i = 0; i < ExpParams.nutrientPop; i++)
+		{
+			addNutrient();
+		}
+
+		nutrientenergywaiting = 0.0;
+		Simulator.checkpoint();
 	}
 }
@@ -397,4 +469,71 @@
 // -------------------------------- nutrient end --------------------------------
 
+// -------------------------------- step begin --------------------------------
+
+function onStep()
+{
+	if (ExpParams.logging == 1)
+	{
+		createStatistics();
+	}
+
+	nutrientGrowth();
+
+	//reproduction --------------------------------------------
+	reprocounter += 1;
+	if (reprocounter > ExpParams.repro_time)
+	{
+		reprocounter = 0;
+		reproduce_parents(0);
+		reproduce_parents(1);
+	}
+
+	//check for extinction -----------------------------------------------
+	if (Populations[0].size == 0)
+	{
+		if (ExpParams.autorestart)
+		{
+			Simulator.print("no more creatures, restarting...");
+			onExpInit();
+		}
+		else
+		{
+			Simulator.print("no more creatures, stopped.");
+			Simulator.stop();
+		}
+	}
+}
+
+function createStatistics()
+{	
+	var number_ploidy = [0, 0];
+	var number_species = [0, 0];
+	var e_inc = [0.0, 0.0];
+	var e_nut = 0.0;
+
+	for (var i = 0; i < Populations[0].size; i++)
+	{
+		var cr = Populations[0].get(i);
+		var gen = cr.user2["gen"];
+		number_ploidy[gen] = number_ploidy[gen] + 1;
+		var species = cr.user2["species"];
+		number_species[species] = number_species[species] + 1; 
+		e_inc[gen] = e_inc[gen] + cr.energy;
+	}
+
+	for (var i = 0; i < Populations[1].size; i++)
+	{
+		var cr = Populations[1].get(i);
+		e_nut += cr.energy;
+	}
+
+	var log_numbers = [number_ploidy[0], number_ploidy[1], Populations[1].size];
+	var log_species = [number_species[0], number_species[1]];
+	var log_energy = [e_inc[0], e_inc[1], e_nut];
+
+	log(log_numbers, "log_sizes.txt");
+	log(log_species, "log_species.txt");
+	log(log_energy, "log_energy.txt");
+}
 
 function log(tolog, fname)
@@ -410,6 +549,5 @@
 }
 
-
-
+// -------------------------------- step end --------------------------------
 
 @include "standard_events.inc"
@@ -418,43 +556,225 @@
 
 prop:
-id:max_age
-name:Maximal age
-type:d 100 1000 500
-group:Foraminifera
-
-prop:
-id:worldsize
+id:e_repro_cost_haplo
+name:cost of reproduction
+type:f 0.1 0.9 0.5
+group:Foraminifera
+
+prop:
+id:e_repro_cost_diplo
+name:cost of reproduction
+type:f 0.1 0.9 0.3
+group:Foraminifera
+
+prop:
+id:chamber_proculus_haplo
+name:size of proculus
+type:f
+group:Foraminifera
+
+prop:
+id:chamber_proculus_diplo
+name:size of proculus
+type:f
+group:Foraminifera
+
+prop:
+id:chamber_difference_haplo
+name:difference in size between subsequent chambers
+type:f
+group:Foraminifera
+
+prop:
+id:chamber_difference_diplo
+name:difference in size between subsequent chambers
+type:f
+group:Foraminifera
+
+prop:
+id:hunted_prob
+name:Probability of being hunted
+type:f 0 1 0
+group:Forminifera
+
+prop:
+id:zone1_range
+name:Zone 1 range 
+type:f 0 200
+group:Foraminifera
+
+prop:
+id:zone2_range
+name:Zone 2 range
+type:f 0 3000
+group:Foraminifera
+
+prop:
+id:colors
+name:Haploid and diploid colors
+type:x
+group:Foraminifera
+
+prop:
+id:min_repro_energ_haplo
+name:Min reproduction energy of forams
+type:f
+group:Foraminifera
+
+prop:
+id:min_repro_energ_diplo
+name:Min reproduction energy of forams
+type:f
+group:Foraminifera
+
+prop:
+id:repro_prob
+name:Probability of reproduction
+type:f 0 1 0.8
+group:Foraminifera
+
+prop:
+id:energies0_haplo
+name:Energy of offspring from diploid forams
+type:f
+group:Foraminifera
+
+prop:
+id:energies0_diplo
+name:Energy of offspring from diploid forams
+type:f
+group:Foraminifera
+
+prop:
+id:energy_hib
+name:Energy used for hibernation during one step
+type:f 0 1 0.001
+group:Foraminifera
+
+prop:
+id:energy_move
+name:Energy used for movement during one step
+type:f 0 20 0.001
+group:Foraminifera
+
+prop:
+id:min_vol
+name:Minimal volume for reproduction
+type:f 100 900 100
+group:Foraminifera
+
+prop:
+id:max_size
+name:Maximal size
+type:d 1 10 5 
+group:Foraminifera
+
+prop:
+id:foramPop
+name:Initial forams population size
+type:d 1 1000 100
+group:Foraminifera
+
+prop:
+id:crossprob
+name:Crossover probability
+type:f 0 1 0
+group:Foraminifera
+
+prop:
+id:mutationprob
+name:Mutation probability
+type:f 0 1 0
+group:Foraminifera
+
+prop:
+id:e_death_level
+name:Level of energy ... death
+type:f 0
+group:Foraminifera
+
+
+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:energy_nut
+name:Nutrients's energy
+type:f 0 1000
+group:Energy
+
+prop:
+id:feedtrans
+name:Ingestion multiplier
+type:f 0 100
+group:Energy
+
+prop:
+id:nutrientsize
+name:Nutrients's size
+type:f 0.1
+group:Energy
+
+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:feedtrans
+name:Ingestion multiplier
+group:Energy
+type:f 0 100
+
+prop:
+id:nutrientsize
+name:Nutrients's size
+group:Energy
+type:f 0.1
+
+prop:
+id:nutrientPop
+name:Nutrients population size
+group:Energy
+type:d 1 1000 10
+
+
+prop:
+id:world_size
 name:World size
 type:d 10 1000 20
-
-prop:
-id:growth_step
-name:Growth step
-type:d -1 10000 1000
-group:Foraminifera
-help:You can turn off growth by setting this param to -1
-
-prop:
-id:rads
-name:Haploid and diploid radius
-type:x
-group:Foraminifera
-
-prop:
-id:minage
-name:Min reproduction age of forams
-type:x
-group:Foraminifera
-
-prop:
-id:minenerg
-name:Min reproduction energy of forams
-type:x
-group:Foraminifera
-
-prop:
-id:nutrient_range
-name:Range of nutrient smell
-type:d 0 10000 10000
+group:World
+
+prop:
+id:stress
+name:Environmental stress
+type:d 0 1 1
+group:World
+
+prop:
+id:repro_trigger
+name:Reproduction trigger
+type:d 0 1 1
+group:World
+
 
 prop:
@@ -462,52 +782,4 @@
 name:Time before reproduction
 type:d 0 1000
-
-prop:
-id:popsize
-name:Initial forams population size
-type:d 1 1000 100
-group:Foraminifera
-
-prop:
-id:energy0h
-name:Number of offspring from haploid forams
-type:d
-group:Foraminifera
-
-prop:
-id:energy0d
-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
-group:Foraminifera
-
-prop:
-id:crossprob
-name:Crossover probability
-type:f 0 1 0
-group:Foraminifera
-
-prop:
-id:mutationprob
-name:Mutation probability
-type:f 0 1 0
-group:Foraminifera
-
-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:
@@ -522,48 +794,4 @@
 -1   = just above the bottom~
 
-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:Nutrients's energy
-group:Energy
-type:f 0 1000
-
-prop:
-id:feedtrans
-name:Ingestion multiplier
-group:Energy
-type:f 0 100
-
-prop:
-id:nutrientgen
-name:Nutrients's genotype
-group:Energy
-type:s 1
-
-prop:
-id:nutrientsize
-name:Nutrients's size
-group:Energy
-type:f 0.1
-
-prop:
-id:nutrientPop
-name:Nutrients population size
-group:Energy
-type:d 1 1000 10
-
 state:
 id:nutrient
Index: /experiments/frams/foraminifera/data/scripts/foraminifera.inc
===================================================================
--- /experiments/frams/foraminifera/data/scripts/foraminifera.inc	(revision 421)
+++ /experiments/frams/foraminifera/data/scripts/foraminifera.inc	(revision 422)
@@ -2,13 +2,95 @@
 //real proportions
 
-// -------------------------------- step begin --------------------------------
-
-function reproduce_haploid(parent, parent2)
-{
-	var number = parent.user2["Va"] / ExpParams.energy0d + parent2.user2["Va"] / ExpParams.energy0d;
+function init_chambers()
+{
+	colors = ["1.0,1.0,0.0","1.0,0.5,0.0"];
+	chambers = [ ["//0\np:sh=1,",
+	"p:0.98089325428009, 0.00591040402650833, 0.00389722990803421,",
+	"p:1.90962779521942, -0.256769120693207, -0.16194811463356,",
+	"p:2.63965249061584, -0.727959632873535, -0.609036147594452,",
+	"p:3.17575979232788, -1.34843015670776, -1.14828503131866,",
+	"p:3.55273032188416, -2.22369408607483, -1.3917418718338,",
+	"p:3.64916682243347, -3.11888360977173, -1.01666414737701,",
+	"p:3.50461649894714, -3.84039807319641, -0.377427101135254,",
+	"p:3.15921688079834, -4.50001525878906, 0.261153399944305,",
+	"p:2.51528453826904, -5.16421365737915, 0.59241509437561,"],
+	["//0\np:sh=1,",
+	"p:1.08020961284637, -0.0597195439040661, -0.0393781512975693,",
+	"p:1.08020961284637, -0.0597195439040661, -0.0393781512975693,",
+	"p:0.615013539791107, 0.778662621974945, 0.535521030426025,",
+	"p:0.488581955432892, 0.826426684856415, -0.381044268608093,",
+	"p:0.732419908046722, -0.0084995785728097, -1.02214300632477,",
+	"p:1.35288727283478, 0.875738024711609, -1.03719782829285,",
+	"p:0.342692613601685, 0.938660383224487, -1.45657968521118,",
+	"p:1.0958571434021, 0.316927701234818, -1.813929438591,",
+	"p:0.903768002986908, 1.11856341362, -2.53161096572876,",
+	"p:0.21014116704464, 0.295340299606323, -2.45328187942505,"] ];
+}
+
+function createForamGenotype(gen, species, chamber_num)
+{
+	var rad = getProperty(gen, "chamber_proculus"); 
+	var geno = chambers[species][0] + "sx=" + rad + ",sy=" + rad + ",sz=" + rad + ", rz=3.14159265358979,vr=" + colors[gen];
+
+	chamber_num = Math.min(chamber_num, chambers[species].size - 1);
+
+	for (var i = 0; i < chamber_num; i++)
+	{
+		rad = getProperty(gen, "chamber_proculus") + getProperty(gen, "chamber_difference") * (i + 1); 
+		geno += "\n" +  chambers[species][i+1] + "sh=1,sx=" + rad + ",sy=" + rad + ",sz=" + rad + ",vr=" + colors[gen];
+	}
+
+	for (var i = 0; i < chamber_num; i++)
+	{
+		geno += "\n" +  "j:"+ i +", "+ (i+1) +", sh=1";
+	}
+	if (species == 1) geno += "\nn:p=0,d=\"S\"";
+
+	return geno;
+}
+
+function setGenotype(mode)
+{
+	if (mode["opt"] == 0) //initial
+	{
+		mode["cr"].user1 = {"min_repro_energies" : [getProperty(0, "min_repro_energ"), getProperty(1, "min_repro_energ")], "hibernation" : 1 - mode["species"]};
+		mode["cr"].user2 = {"max_energy_level" : getProperty(0,"energies0"), "gen" : 0,  "hibernated" : 0, "species" : mode["species"], "reproduce" : 0};
+	}
+	else if (mode["opt"]  == 1) //child
+	{
+		mode["cr"].user2 = {"max_energy_level" : getProperty(1 - mode["parent_user2"]["gen"],"energies0"), "gen" : 1 - mode["parent_user2"]["gen"],  "hibernated" : 0, "species" : mode["parent_user2"]["species"], "reproduce" : 0};
+		mode["cr"].user1 = mode["parent_user1"];
+	}
+	else //grow
+	{
+		mode["cr"].user1 = mode["parent_user1"];
+		mode["cr"].user2 = mode["parent_user2"];
+	}
+}
+
+function reproduce_haploid(parent, parent2, clone)
+{	
+	var number, energy0, new_user1, gen;
+	if (clone == 1)
+	{
+		energy0 = getProperty(0,"energies0");
+		number = getProperty(1, "e_repro_cost") * parent.energy / energy0;
+		new_user1 = parent.user1;
+		parent.user2["gen"] = 1 - parent.user2["gen"]; //because of reversal of "gen" in createOffspring function
+		gen = parent.user2["gen"];
+	}
+	else
+	{
+		energy0 = getProperty(1,"energies0"); 
+		number = getProperty(parent.user2["gen"], "e_repro_cost") * parent.energy / energy0 + getProperty(parent.user2["gen"], "e_repro_cost") * parent2.energy / energy0;
+		new_user1 = [parent.user1, parent2.user1];
+		gen = 1 - parent.user2["gen"];
+	}
+
+	Simulator.print("number of offspring: " + number);
 
 	for (var j = 0; j < number; j++)
 	{
-		createOffspring(ExpParams.gend, ExpParams.energy0d, [parent.user1, parent2.user1], {"Va" : ExpParams.energy0d, "gen" : 1 , "growth_step" : ExpParams.growth_step, "rsize": ExpParams.rads[1], "vinit": ExpParams.energy0d}); //TODO genes from both generations in user1
+		createOffspring(createForamGenotype(gen, parent.user2["species"], 0), energy0, new_user1, parent.user2); 
 	}
 }
@@ -16,5 +98,9 @@
 function reproduce_diploid(parent)
 {
-	var number = parent.user2["Va"] / ExpParams.energy0h;
+	var energy0 = getProperty(0,"energies0");
+	var number = getProperty(parent.user2["gen"], "e_repro_cost") * parent.energy / energy0;
+
+	Simulator.print("number of offspring: " + number);
+
 	for (var j = 0; j < number / 2; j++)
 	{
@@ -23,5 +109,5 @@
 		if (Math.rnd01 < ExpParams.crossprob)
 		{
-			crossover(parent, "minenergy");
+			crossover(parent, "min_repro_energies");
 			crossed = 1;
 		}
@@ -29,5 +115,5 @@
 		for (var k = 0; k < 2; k++)
 		{
-			createOffspring(ExpParams.genh, ExpParams.energy0h, {"minenergy" : ExpParams.minenerg[0], "minage": ExpParams.minage[0]}, {"Va" : ExpParams.energy0h, "gen" : 0 , "growth_step" : ExpParams.growth_step, "rsize" : ExpParams.rads[0], "vinit": ExpParams.energy0h}); //TODO different vamin and amin for haploids and diploids?
+			createOffspring(createForamGenotype(1 - parent.user2["gen"], parent.user2["species"], 0), energy0, parent.user1[0], parent.user2); 
 		}
 
@@ -35,5 +121,5 @@
 		if (crossed == 1)
 		{
-			crossover(parent, "minenergy");
+			crossover(parent, "min_repro_energies");
 			crossed = 0;
 		}
@@ -42,47 +128,6 @@
 }
 
-function crossover(parent, gene)
-{
-	var tmp = parent.user1[0][gene];
-	parent.user1[0][gene] = parent.user1[1][gene];
-	parent.user1[1][gene] = tmp;
-}
-
-
-function createOffspring(geno, energy, new_user1, new_user2)
-{
-	var cr = Populations[0].add(geno);
-	cr.energy0 = energy;
-	cr.energy = cr.energy0;
-	setGenotype(cr, new_user1, new_user2);
-	placeRandomlyNotColliding(cr);
-}
-
-function onStep()
-{
-
-	if (ExpParams.logging == 1)
-	{
-		createStatistics();
-	}
-
-	//nutrient growth ---------------------------------------------
-	nutrientenergywaiting = nutrientenergywaiting + ExpParams.feedrate;
-	if (nutrientenergywaiting > ExpParams.feede0)
-	{
-		for (var i = 0; i < ExpParams.nutrientPop; i++)
-		{
-			addNutrient();
-		}
-
-		nutrientenergywaiting = 0.0;
-		Simulator.checkpoint();
-	}
-
-	//reproduction --------------------------------------------
-	reprocounter += 1;
-	if (reprocounter > ExpParams.repro_time)
-	{
-		reprocounter = 0;
+function reproduce_parents(species)
+{
 		var parent1 = null;
 		var parent2 = null;
@@ -90,10 +135,9 @@
 		for (var i = pop.size-1; i >= 0; i--)
 		{
-   			if (pop[i].signals.size > 0) 
+   			if (pop[i].user2["reproduce"] == 1 && pop[i].user2["species"] == species) 
    			{ 
-				if (pop[i].user2["gen"]==1)
-				{
-					reproduce_diploid(pop[i]);
-					pop.kill(i);
+				if ((pop[i].user2["gen"]==1) || ((pop[i].user2["gen"]==0) && ExpParams.stress == 0))
+				{
+					continue;
 				}
       				else if (parent1 == null)
@@ -107,5 +151,7 @@
 				else
 				{
-					reproduce_haploid(parent1, parent2);
+					reproduce_haploid(parent1, parent2, 0);
+					print_repro_info(parent1);
+					print_repro_info(parent2);
 					pop.kill(parent1);
 					pop.kill(parent2);
@@ -116,70 +162,96 @@
    			} 
 		}
-	}
-
-	//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();
-		}
-	}
-}
-
-function createStatistics()
-{
-	var haploids = 0;
-	var diploids = 0;
-	var e_inc_h = 0.0;
-	var e_inc_d = 0.0;
-	var e_nut = 0.0;
-	var size_h = 0.0;
-	var size_d = 0.0;
-	var vmin_h = 0.0;
-	var vmin_d = 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;
-			size_h += ExpParams.rads[0]; //TODO change of size dependent on gene
-			vmin_h += cr.user1["minenergy"];
-		}
-		else if (cr.user2["gen"] == 1)
-		{
-			diploids += 1;
-			e_inc_d += cr.energy;
-			size_d += ExpParams.rads[1]; //TODO change of size dependent on gene
-			vmin_d += cr.user1[0]["minenergy"];
-		}
-	}
-
-	for (var i = 0; i < Populations[1].size; i++)
-	{
-		var cr = Populations[1].get(i);
-		e_nut += cr.energy;
-	}
-
-	var l1 = [haploids, diploids, Populations[1].size];
-	var l2 = [e_inc_h, e_inc_d, e_nut];
-	var dp = diploids;
-	var hp = haploids;
-	if (dp == 0) dp = 0.000001;
-	if (hp == 0) hp = 0.000001;
-	var l3 = [size_h / hp, vmin_h / hp, size_d / dp, vmin_d / dp];
-
-	log(l1, "log_sizes.txt");
-	log(l2, "log_energy.txt");
-	log(l3, "log_sizes_v.txt");
-}
-// -------------------------------- step end --------------------------------
+}
+
+function readyToRepro(cr)
+{
+	var reproduced = 1;
+	
+	
+	if (cr.user2["gen"] == 1)
+	{
+		reproduce_diploid(cr);
+	}
+
+	else if (ExpParams.stress == 0)
+	{
+		reproduce_haploid(cr, null, 1);
+	}
+
+	else
+	{
+		if (cr.signals.size == 0)
+		{
+			cr.signals.add("repro"+cr.user2["species"]);
+			cr.signals[0].power = 1;
+		}
+		reproduced = 0;
+		cr.user2["reproduce"] = 1;
+	}
+
+	if (reproduced == 1)
+	{
+		print_repro_info(cr);
+		Populations[0].kill(cr);
+	}
+
+	return reproduced;
+}
+
+function print_repro_info(cr)
+{
+	Simulator.print("Reproduced " + cr.user2["gen"] + " of species " + cr.user2["species"] + " energy: " + cr.energy);
+}
+
+function foramReproduce(cr)
+{
+	var properEnergy = 0;
+	var reproduced = 0;
+
+	if (cr.user2["gen"] == 0)
+	{
+		properEnergy = ( cr.energy >= cr.user1["min_repro_energies"][cr.user2["gen"]] );
+	}
+	else
+	{
+		properEnergy = ( cr.energy >= cr.user1[0]["min_repro_energies"][cr.user2["gen"]] ); //TODO gene selection
+	}
+
+	//if creature has proper energy
+	if ( properEnergy && cr.signals.size == 0)
+	{
+		//reproduce with probability repro_prob
+		if (Math.rnd01 <= ExpParams.repro_prob) //TODO env trigger
+		{
+			reproduced = readyToRepro(cr);
+		}
+		else if (cr.signals.receive("repro"+cr.user2["species"]) > 0)
+		{
+			reproduced = readyToRepro(cr);
+		}
+		if (reproduced == 1)
+				return;
+	}
+
+	else if (!properEnergy)
+	{
+		cr.signals.clear();
+		cr.user2["reproduce"] = 0; 
+	}
+}
+
+function crossover(parent, gene)
+{
+	var tmp = parent.user1[0][gene];
+	parent.user1[0][gene] = parent.user1[1][gene];
+	parent.user1[1][gene] = tmp;
+}
+
+function createOffspring(geno, energy, parent_user1, parent_user2)
+{
+	var cr = Populations[0].add(geno);
+	cr.energy0 = energy;
+	cr.energy = cr.energy0;
+	setGenotype({"cr" : cr, "parent_user1" : parent_user1, "parent_user2" : parent_user2, "opt" : 1});
+	placeRandomlyNotColliding(cr);
+}
Index: /experiments/frams/foraminifera/data/scripts/foraminifera.show
===================================================================
--- /experiments/frams/foraminifera/data/scripts/foraminifera.show	(revision 421)
+++ /experiments/frams/foraminifera/data/scripts/foraminifera.show	(revision 422)
@@ -2,7 +2,10 @@
 name:Reproduction of benthic foraminifera
 info:~
-Foraminifers are shown as green balls. Nutrients are tiny white boxes.
-Foraminifers move towards nearest nutrients and try to accumulate a sufficient amount of energy to reproduce.
-Haploid and diploid generations alternate. Diploid foraminifers have orange marks.
+There are two species of Foraminiera: longitudal and coiled. First chamber of the longitudal species has 
+orange marks. Haploid and diploid generations alternate in both species. All chambers of the haploid generation
+have the same size. In the diploid generation subsequent chambers are bigger than their predecessors.
+Nutrients are green disks. Foraminifers move towards nearest nutrients and try to accumulate a sufficient
+amount of energy to reproduce.
+
 More information at www.framsticks.com/foraminifera
 ~
@@ -16,50 +19,16 @@
 	GLDisplay.minfps = 10;
 }
-
-function ShowParams_minimalVolume_set()
+function ShowParams_nutrientPop_set()
 {
-	switch (ShowParams.minimalVolume)
+	switch (ShowParams.nutrientPop)
 	{
 	case 0:
-		ExpParams.v_min_h = 300;
-		ExpParams.v_min_d = 300;
+		ExpParams.nutrientPop = 5;
 		break;
 	case 1:
-		ExpParams.v_min_h = 150;
-		ExpParams.v_min_d = 500;
-		break;
-	}
-}
-
-function ShowParams_offspingNumber_set()
-{
-	switch (ShowParams.offspingNumber)
-	{
-	case 0:
-		ExpParams.ofnumh = 300;
-		ExpParams.ofnumd = 300;
-		break;
-	case 1:
-		ExpParams.ofnumh = 150;
-		ExpParams.ofnumd = 500;
-		break;
-	}
-}
-
-function ShowParams_populationSize_set()
-{
-	switch (ShowParams.populationSize)
-	{
-	case 0:
-		ExpParams.psize = 5;
-		break;
-	case 1:
-		ExpParams.psize = 10;
+		ExpParams.nutrientPop = 10;
 		break;
 	case 2:
-		ExpParams.psize = 15;
-		break;
-	case 3:
-		ExpParams.psize = 20;
+		ExpParams.nutrientPop = 15;
 		break;
 	}
@@ -71,11 +40,56 @@
 	{
 	case 0:
-		ExpParams.feedrate = 0.5;
+		ExpParams.feedrate = 0.001;
 		break;
 	case 1:
-		ExpParams.feedrate = 0.7;
+		ExpParams.feedrate = 0.0025;
 		break;
 	case 2:
-		ExpParams.feedrate = 0.9;
+		ExpParams.feedrate = 0.004;
+		break;
+	}
+}
+
+function ShowParams_feedTrans_set()
+{
+	switch (ShowParams.feedTrans)
+	{
+	case 0:
+		ExpParams.feedtrans = 0.01;
+		break;
+	case 1:
+		ExpParams.feedtrans = 0.05;
+		break;
+	case 2:
+		ExpParams.feedtrans = 0.1;
+		break;
+	}
+}
+
+function ShowParams_nutrientEnerg_set()
+{
+	switch (ShowParams.nutrientEnerg)
+	{
+	case 0:
+		ExpParams.energy_nut = 0.5;
+		break;
+	case 1:
+		ExpParams.energy_nut = 1.5;
+		break;
+	case 2:
+		ExpParams.energy_nut = 3.0;
+		break;
+	}
+}
+
+function ShowParams_stress_set()
+{
+	switch (ShowParams.stress)
+	{
+	case 0:
+		ExpParams.stress = 0;
+		break;
+	case 1:
+		ExpParams.stress = 1;
 		break;
 	}
@@ -84,22 +98,26 @@
 ~
 
-
 prop:
-id:minimalVolume
-name:Min reproduction energy haploid/diploid
-type:f 0 1 ~300 / 300~150 / 500
-
-prop:
-id:populationSize
-name:Initial population size
-type:d 0 3 ~5~10~15~20
-
-prop:
-id:offspingNumber
-name:Number of offspring haploi/diploid
-type:d 0 2 ~20 / 4~10 / 5
+id:nutrientPop
+name:Nutrients amount
+type:d 0 2 1 ~5~10~15
 
 prop:
 id:feedRate
 name:Feeding rate
-type:d 0 2 ~50~70~90
+type:d 0 2 1 ~1~2~3
+
+prop:
+id:feedTrans
+name:Energy transfer
+type:d 0 2 1 ~0.01~0.05~0.1
+
+prop:
+id:nutrientEnerg
+name:Nutrient energy
+type:d 0 2 1 ~0.5~1.5~3
+
+prop:
+id:stress
+name:Stress 
+type:d 0 1 1
