Index: /cpp/frams/genetics/fS/fS_conv.h
===================================================================
--- /cpp/frams/genetics/fS/fS_conv.h	(revision 999)
+++ /cpp/frams/genetics/fS/fS_conv.h	(revision 1000)
@@ -19,6 +19,6 @@
 		name = "Solid encoding";
 
-		in_format = 'S';
-		out_format = '0';
+		in_format = "S";
+		out_format = "0s";
 		mapsupport = 1;
 	}
Index: /cpp/frams/genetics/fS/fS_general.cpp
===================================================================
--- /cpp/frams/genetics/fS/fS_general.cpp	(revision 999)
+++ /cpp/frams/genetics/fS/fS_general.cpp	(revision 1000)
@@ -11,8 +11,25 @@
 #include "frams/neuro/neurolibrary.h"
 #include "../genooperators.h"
+#include "common/nonstd_math.h"
+#include "part_distance_estimator.h"
 
 int fS_Genotype::precision = 4;
 bool fS_Genotype::TURN_WITH_ROTATION = false;
 
+const std::map<string, double> defaultValues = {
+		{INGESTION,      0.5},//Model::getDefPart().ingest },
+		{FRICTION,       0.5},//Model::getDefPart().friction},
+		{STIFFNESS,	 	 0.5},//Model::getDefJoint().stif},
+		{ROT_X,          0.0},
+		{ROT_Y,          0.0},
+		{ROT_Z,          0.0},
+		{RX,             0.0},
+		{RY,             0.0},
+		{RZ,             0.0},
+		{SIZE,           1.0},
+		{SIZE_X,         0.5},//Model::getDefPart().scale.x},
+		{SIZE_Y,         0.5},//Model::getDefPart().scale.y},
+		{SIZE_Z,         0.5}//Model::getDefPart().scale.z}
+};
 
 double fS_stod(const string&  str, int start, size_t* size)
@@ -52,14 +69,7 @@
 }
 
-void rotateVector(Pt3D &vector, const Pt3D &rotation)
-{
-	Orient rotmatrix = Orient_1;
-	rotmatrix.rotate(rotation);
-	vector = rotmatrix.transform(vector);
-}
-
 void State::rotate(const Pt3D &rotation)
 {
-       rotateVector(v, rotation);
+       fS_Utils::rotateVector(v, rotation);
        v.normalize();
 }
@@ -111,8 +121,9 @@
 }
 
-Node::Node(Substring &restOfGeno, Node *_parent)
-{
+Node::Node(Substring &restOfGeno, Node *_parent, GenotypeParams _genotypeParams)
+{
+	partDescription = new Substring(restOfGeno);
+	genotypeParams = _genotypeParams;
 	parent = _parent;
-	partDescription = new Substring(restOfGeno);
 
 	try
@@ -289,169 +300,4 @@
 }
 
-double avg(double a, double b)
-{
-	return 0.5 * (a + b);
-}
-
-double min3(Pt3D p)
-{
-	double tmp = p.x;
-	if (p.y < tmp)
-		tmp = p.y;
-	if (p.z < tmp)
-		tmp = p.z;
-	return tmp;
-}
-
-double max3(Pt3D p)
-{
-	double tmp = p.x;
-	if (p.y > tmp)
-		tmp = p.y;
-	if (p.z > tmp)
-		tmp = p.z;
-	return tmp;
-}
-
-double getSphereCoordinate(double dimension, double sphereDiameter, double index, int count)
-{
-	if (count == 1)
-		return 0;
-	return (dimension - sphereDiameter) * (index / (count - 1) - 0.5);
-}
-
-Pt3D *findSphereCenters(int &sphereCount, double &sphereRadius, Pt3D radii, Pt3D rotations)
-{
-	double sphereRelativeDistance = SPHERE_RELATIVE_DISTANCE;
-	double minRadius = min3(radii);
-	if(minRadius <= 0)
-	    throw fS_Exception("Invalid part size", 0);
-	double maxRadius = max3(radii);
-	if (MAX_DIAMETER_QUOTIENT > maxRadius / minRadius)
-		sphereRadius = minRadius;
-	else
-	{
-		// When max radius is much bigger than min radius
-		sphereRelativeDistance = 1.0;   // Make the spheres adjacent to speed up the computation
-		sphereRadius = maxRadius / MAX_DIAMETER_QUOTIENT;
-	}
-	double sphereDiameter = 2 * sphereRadius;
-
-	double *diameters = new double[3] {2 * radii.x, 2 * radii.y, 2 * radii.z};
-	int counts[3];
-	for (int i = 0; i < 3; i++)
-	{
-		counts[i] = 1;
-		if (diameters[i] > sphereDiameter)
-			counts[i] += ceil((diameters[i] - sphereDiameter) / sphereDiameter / sphereRelativeDistance);
-	}
-
-	sphereCount = counts[0] * counts[1] * counts[2];
-	double x, y, z;
-	int totalCount = 0;
-	Pt3D *centers = new Pt3D[sphereCount];
-	for (double xi = 0; xi < counts[0]; xi++)
-	{
-		x = getSphereCoordinate(diameters[0], sphereDiameter, xi, counts[0]);
-		for (double yi = 0; yi < counts[1]; yi++)
-		{
-			y = getSphereCoordinate(diameters[1], sphereDiameter, yi, counts[1]);
-			for (double zi = 0; zi < counts[2]; zi++)
-			{
-				z = getSphereCoordinate(diameters[2], sphereDiameter, zi, counts[2]);
-				centers[totalCount] = Pt3D(x, y, z);
-				rotateVector(centers[totalCount], rotations);
-				totalCount++;
-			}
-		}
-	}
-	delete[] diameters;
-	return centers;
-}
-
-int isCollision(Pt3D *centersParent, Pt3D *centers, int parentSphereCount, int sphereCount, Pt3D &vector,
-				double distanceThreshold)
-{
-	double upperThreshold = distanceThreshold;
-	double lowerThreshold = SPHERE_DISTANCE_TOLERANCE * distanceThreshold;
-	double distance;
-	double dx, dy, dz;
-	bool existsAdjacent = false;
-	Pt3D *tmpPoint;
-	for (int sc = 0; sc < sphereCount; sc++)
-	{
-		Pt3D shiftedSphere = Pt3D(centers[sc]);
-		shiftedSphere += vector;
-		for (int psc = 0; psc < parentSphereCount; psc++)
-		{
-			tmpPoint = &centersParent[psc];
-			dx = shiftedSphere.x - tmpPoint->x;
-			dy = shiftedSphere.y - tmpPoint->y;
-			dz = shiftedSphere.z - tmpPoint->z;
-			distance = sqrt(dx * dx + dy * dy + dz * dz);
-
-			if (distance <= upperThreshold)
-			{
-				if (distance >= lowerThreshold)
-					existsAdjacent = true;
-				else
-				{
-					return COLLISION;
-				}
-			}
-		}
-	}
-	if (existsAdjacent)
-		return ADJACENT;
-	else
-		return DISJOINT;
-}
-
-double Node::getDistance()
-{
-	Pt3D size = calculateSize();
-	Pt3D parentSize = parent->calculateSize();	// Here we are sure that parent is not nullptr
-	int parentSphereCount, sphereCount;
-	double parentSphereRadius, sphereRadius;
-	Pt3D *centersParent = findSphereCenters(parentSphereCount, parentSphereRadius, parentSize, parent->getRotation());
-	Pt3D *centers = findSphereCenters(sphereCount, sphereRadius, size, getRotation());
-
-	double distanceThreshold = sphereRadius + parentSphereRadius;
-	double minDistance = 0.0;
-	double maxDistance = 2 * (max3(parentSize) + max3(size));
-	double currentDistance = avg(maxDistance, minDistance);
-	int result = -1;
-	int iterationNo = 0;
-	while (result != ADJACENT)
-	{
-		iterationNo++;
-		Pt3D currentVector = state->v * currentDistance;
-		result = isCollision(centersParent, centers, parentSphereCount, sphereCount, currentVector, distanceThreshold);
-
-		if (result == DISJOINT)
-		{
-			maxDistance = currentDistance;
-			currentDistance = avg(currentDistance, minDistance);
-		} else if (result == COLLISION)
-		{
-			minDistance = currentDistance;
-			currentDistance = avg(maxDistance, currentDistance);
-		}
-
-		if(maxDistance <= 0 || iterationNo > 1000)
-			throw fS_Exception("Computing of distances between parts failed", 0);
-		if (currentDistance > maxDistance)
-		{
-			throw fS_Exception("Internal error; then maximal distance between parts exceeded.", 0);
-		}
-		if (currentDistance < minDistance)
-			throw fS_Exception("Internal error; the minimal distance between parts exceeded.", 0);
-
-	}
-
-	delete[] centersParent;
-	delete[] centers;
-	return currentDistance;
-}
 
 void Node::getState(State *_state)
@@ -469,5 +315,5 @@
 	{
 		char mod = it->first;
-		double multiplier = pow(MODIFIER_MULTIPLIER, it->second);
+		double multiplier = pow(genotypeParams.modifierMultiplier, it->second);
 		if (mod == MODIFIERS[0])
 			state->ing *= multiplier;
@@ -497,5 +343,5 @@
 	for (int i = 0; i < int(branches.size()); i++)
 	{
-		children.push_back(new Node(branches[i], this));
+		children.push_back(new Node(branches[i], this, genotypeParams));
 	}
 }
@@ -581,8 +427,8 @@
 		return false;
 
-	if (partType == Part::Shape::SHAPE_ELLIPSOID && max3(size) != min3(size))
+	if (partType == Part::Shape::SHAPE_ELLIPSOID && fS_Utils::max3(size) != fS_Utils::min3(size))
 		// When not all radii have different values
 		return false;
-	if (partType == Part::Shape::SHAPE_CYLINDER && size.x != size.y)
+	if (partType == Part::Shape::SHAPE_CYLINDER && size.y != size.z)
 		// If base radii have different values
 		return false;
@@ -619,5 +465,5 @@
 		Neuro *neuro = new Neuro(*neurons[i]);
 		model.addNeuro(neuro);
-		if (neuro->getClass()->preflocation == 2 && parent != nullptr)
+		if (neuro->getClass()->preflocation == NeuroClass::PREFER_JOINT && parent != nullptr)
 		{
 			neuro->attachToJoint(model.getJoint(model.getJointCount() - 1));
@@ -732,7 +578,6 @@
 			result += it->first.c_str();                    // Add parameter key to string
 			result += PARAM_KEY_VALUE_SEPARATOR;
-			string value_text = std::to_string(it->second);
 			// Round the value to two decimal places and add to string
-			result += value_text.substr(0, value_text.find(".") + fS_Genotype::precision).c_str();
+			result += doubleToString(it->second, fS_Genotype::precision).c_str();
 		}
 		result += PARAM_END;
@@ -754,18 +599,4 @@
 }
 
-
-bool Node::changeSizeParam(string key, bool ensureCircleSection)
-{
-	double oldValue = getParam(key);
-	params[key] = GenoOperators::mutateCreep('f', params[key], minValues.at(key), maxValues.at(key), true);
-	if (!ensureCircleSection || isPartSizeValid())
-		return true;
-	else
-	{
-		params[key] = oldValue;
-		return false;
-	}
-}
-
 void Node::getAllNodes(vector<Node *> &allNodes)
 {
@@ -782,11 +613,20 @@
 }
 
-fS_Genotype::fS_Genotype(const string &genotype)
+fS_Genotype::fS_Genotype(const string &geno)
 {
 	try
 	{
-		string geno = genotype.c_str();
-		Substring substring(geno.c_str(), 0, geno.length());
-		startNode = new Node(substring, nullptr);
+		GenotypeParams genotypeParams;
+		genotypeParams.modifierMultiplier = 1.1;
+
+		size_t modeSeparatorIndex = geno.find(MODE_SEPARATOR);
+		if (modeSeparatorIndex == string::npos)
+			throw fS_Exception("Genotype parameters missing", 0);
+
+		genotypeParams.modifierMultiplier = fS_stod(geno, 0, &modeSeparatorIndex);
+
+		int genoStart = modeSeparatorIndex + 1;
+		Substring substring(geno.c_str(), genoStart, geno.length() - genoStart);
+		startNode = new Node(substring, nullptr, genotypeParams);
 		validateNeuroInputs();
 	}
@@ -859,5 +699,9 @@
 {
 	SString geno;
-	geno.reserve(100);     // Provide a small buffer from the start to improve performance
+	geno.reserve(100);
+
+	geno += doubleToString(startNode->genotypeParams.modifierMultiplier, fS_Genotype::precision).c_str();
+	geno += MODE_SEPARATOR;
+
 	startNode->getGeno(geno);
 	return geno;
Index: /cpp/frams/genetics/fS/fS_general.h
===================================================================
--- /cpp/frams/genetics/fS/fS_general.h	(revision 999)
+++ /cpp/frams/genetics/fS/fS_general.h	(revision 1000)
@@ -16,4 +16,5 @@
 /** @name Values of constants used in encoding */
 //@{
+#define MODE_SEPARATOR ':'
 #define BRANCH_START '('
 #define BRANCH_END ')'
@@ -35,23 +36,4 @@
 	RIGHT = 1
 };
-
-/** @name Every modifier changes the underlying value by this multiplier */
-const double MODIFIER_MULTIPLIER = 1.1;
-/**
- * Used in finding the proper distance between the parts
- * distance between spheres / sphere radius
- * That default value can be changed in certain cases
- * */
-const float SPHERE_RELATIVE_DISTANCE = 0.25;
-/**
- * Used in finding the proper distance between the parts
- * The maximal allowed value for
- * maximal radius of the node / sphere radius
- */
-const int MAX_DIAMETER_QUOTIENT = 30;
-/**
- * The tolerance of the value of distance between parts
- */
-const double SPHERE_DISTANCE_TOLERANCE = 0.99;
 
 
@@ -109,8 +91,7 @@
 const vector<string> PARAMS {INGESTION, FRICTION, ROT_X, ROT_Y, ROT_Z, RX, RY, RZ, SIZE, SIZE_X, SIZE_Y, SIZE_Z,
 							 STIFFNESS};
+const vector<string> SIZE_PARAMS {SIZE, SIZE_X, SIZE_Y, SIZE_Z};
 
 /** @name Default values of node parameters*/
-static const Part defPart = Model::getDefPart();
-static const Joint defJoint = Model::getDefJoint();
 const std::map<Part::Shape, double> volumeMultipliers = {
 		{Part::Shape::SHAPE_CUBOID, 8.0},
@@ -118,51 +99,6 @@
 		{Part::Shape::SHAPE_ELLIPSOID, (4.0 / 3.0) * M_PI},
 };
-const std::map<string, double> defaultValues = {
-		{INGESTION,      defPart.ingest},
-		{FRICTION,       defPart.friction},
-		{STIFFNESS,	 	 defJoint.stif},
-		{ROT_X,          0.0},
-		{ROT_Y,          0.0},
-		{ROT_Z,          0.0},
-		{RX,             0.0},
-		{RY,             0.0},
-		{RZ,             0.0},
-		{SIZE,           1.0},
-		{SIZE_X,         1.0},
-		{SIZE_Y,         1.0},
-		{SIZE_Z,         1.0}
-};
-
-const std::map<string, double> minValues = {
-		{INGESTION,      0},
-		{FRICTION,       0},
-		{STIFFNESS,	 0.0},
-		{ROT_X,          -M_PI},
-		{ROT_Y,          -M_PI},
-		{ROT_Z,          -M_PI},
-		{RX,             -M_PI},
-		{RY,             -M_PI},
-		{RZ,             -M_PI},
-		{SIZE,           0.01},
-		{SIZE_X,         0.01},
-		{SIZE_Y,         0.01},
-		{SIZE_Z,         0.01}
-};
-
-const std::map<string, double> maxValues = {
-		{INGESTION,      1.0},
-		{FRICTION,       1.0},
-		{STIFFNESS,	 0.0},
-		{ROT_X,          M_PI},
-		{ROT_Y,          M_PI},
-		{ROT_Z,          M_PI},
-		{RX,             M_PI},
-		{RY,             M_PI},
-		{RZ,             M_PI},
-		{SIZE,           100.0},
-		{SIZE_X,         100.0},
-		{SIZE_Y,         100.0},
-		{SIZE_Z,         100.0}
-};
+
+extern const std::map<string, double> defaultValues;
 
 /** @name Number of tries of performing a mutation before GENOPER_FAIL is returned */
@@ -318,4 +254,8 @@
 };
 
+struct GenotypeParams{
+	double modifierMultiplier;	// Every modifier changes the underlying value by this multiplier
+};
+
 /**
  * Represents a node in the graph that represents a genotype.
@@ -334,6 +274,7 @@
 	Part *part;     /// A part object built from node. Used in building the Model
 	int partCodeLen; /// The length of substring that directly describes the corresponding part
-
-	std::map<string, double> params; /// The map of all the node params
+	GenotypeParams genotypeParams;
+
+
 	vector<Node *> children;    /// Vector of all direct children
 	std::map<char, int> modifiers;     /// Vector of all modifiers
@@ -432,6 +373,7 @@
 	Part::Shape partType;  /// The type of the part
 	State *state = nullptr; /// The phenotypic state that inherits from ancestors
-
-	Node(Substring &genotype, Node *parent);
+	std::map<string, double> params; /// The map of all the node params
+
+	Node(Substring &genotype, Node *parent, GenotypeParams genotypeParams);
 
 	~Node();
@@ -463,5 +405,5 @@
 	 * @return True if the parameter value was change, false otherwise
 	 */
-	bool changeSizeParam(string paramKey,  bool ensureCircleSection);
+	bool mutateSizeParam(string paramKey,  bool ensureCircleSection);
 
 	/**
Index: /cpp/frams/genetics/fS/fS_oper.cpp
===================================================================
--- /cpp/frams/genetics/fS/fS_oper.cpp	(revision 999)
+++ /cpp/frams/genetics/fS/fS_oper.cpp	(revision 1000)
@@ -12,26 +12,61 @@
 		{
 				{"Genetics: fS",            1, FS_OPCOUNT + 5,},
-				{"fS_mut_add_part",         0, 0, "Add part",                 "f 0 100 10", FIELD(prob[FS_ADD_PART]),             "mutation: probability of adding a part",},
-				{"fS_mut_rem_part",         0, 0, "Remove part",              "f 0 100 10", FIELD(prob[FS_REM_PART]),             "mutation: probability of deleting a part",},
-				{"fS_mut_mod_part",         0, 0, "Modify part",              "f 0 100 10", FIELD(prob[FS_MOD_PART]),             "mutation: probability of changing the part type",},
-				{"fS_mut_change_joint",        0, 0, "Change joint",                "f 0 100 10", FIELD(prob[FS_CHANGE_JOINT]),            "mutation: probability of changing a joint",},
-				{"fS_mut_add_param",        0, 0, "Add param",                "f 0 100 10", FIELD(prob[FS_ADD_PARAM]),            "mutation: probability of adding a parameter",},
-				{"fS_mut_rem_param",        0, 0, "Remove param",             "f 0 100 10", FIELD(prob[FS_REM_PARAM]),            "mutation: probability of removing a parameter",},
-				{"fS_mut_mod_param",        0, 0, "Modify param",             "f 0 100 10", FIELD(prob[FS_MOD_PARAM]),            "mutation: probability of modifying a parameter",},
-				{"fS_mut_mod_mod",          0, 0, "Modify modifier",           "f 0 100 10", FIELD(prob[FS_MOD_MOD]),              "mutation: probability of modifying a modifier",},
-				{"fS_mut_add_neuro",        0, 0, "Add neuron",               "f 0 100 10", FIELD(prob[FS_ADD_NEURO]),            "mutation: probability of adding a neuron",},
-				{"fS_mut_rem_neuro",        0, 0, "Remove neuron",            "f 0 100 10", FIELD(prob[FS_REM_NEURO]),            "mutation: probability of removing a neuron",},
-				{"fS_mut_mod_neuro_conn",        0, 0, "Modify neuron connection",            "f 0 100 10", FIELD(prob[FS_MOD_NEURO_CONNECTION]), "mutation: probability of changing a neuron connection",},
-				{"fS_mut_add_neuro_conn",   0, 0, "Add neuron connection",    "f 0 100 10", FIELD(prob[FS_ADD_NEURO_CONNECTION]), "mutation: probability of adding a neuron connection",},
-				{"fS_mut_rem neuro_conn",   0, 0, "Remove neuron connection", "f 0 100 10", FIELD(prob[FS_REM_NEURO_CONNECTION]), "mutation: probability of removing a neuron connection",},
-				{"fS_mut_mod_neuro_params", 0, 0, "Modify neuron params",     "f 0 100 10", FIELD(prob[FS_MOD_NEURO_PARAMS]),     "mutation: probability of changing a neuron param",},
-				{"fS_circle_section",       0, 0, "Ensure circle section",    "d 0 1 1",    FIELD(ensureCircleSection),           "Ensure that ellipsoids and cylinders have circle cross-section"},
-				{"fS_use_elli",       0, 0, "Use ellipsoids in mutations",    "d 0 1 1",    FIELD(useElli),           "Use ellipsoids in mutations"},
-				{"fS_use_cub",       0, 0, "Use cuboids in mutations",    "d 0 1 1",    FIELD(useCub),           "Use cuboids in mutations"},
-				{"fS_use_cyl",       0, 0, "Use cylinders in mutations",    "d 0 1 1",    FIELD(useCyl),           "Use cylinders in mutations"},
-				{"fS_mut_add_part_strong",       0, 0, "Strong add part mutation",    "d 0 1 1",    FIELD(strongAddPart),           "Add part mutation will produce more parametrized parts"},
+				{"fS_mut_add_part",         0, 0, "Add part",                    "f 0 100 10", FIELD(prob[FS_ADD_PART]),             "mutation: probability of adding a part",},
+				{"fS_mut_rem_part",         0, 0, "Remove part",                 "f 0 100 10", FIELD(prob[FS_REM_PART]),             "mutation: probability of deleting a part",},
+				{"fS_mut_mod_part",         0, 0, "Modify part",                 "f 0 100 10", FIELD(prob[FS_MOD_PART]),             "mutation: probability of changing the part type",},
+				{"fS_mut_change_joint",     0, 0, "Change joint",                "f 0 100 10", FIELD(prob[FS_CHANGE_JOINT]),         "mutation: probability of changing a joint",},
+				{"fS_mut_add_param",        0, 0, "Add param",                   "f 0 100 10", FIELD(prob[FS_ADD_PARAM]),            "mutation: probability of adding a parameter",},
+				{"fS_mut_rem_param",        0, 0, "Remove param",                "f 0 100 10", FIELD(prob[FS_REM_PARAM]),            "mutation: probability of removing a parameter",},
+				{"fS_mut_mod_param",        0, 0, "Modify param",                "f 0 100 10", FIELD(prob[FS_MOD_PARAM]),            "mutation: probability of modifying a parameter",},
+				{"fS_mut_mod_mod",          0, 0, "Modify modifier",             "f 0 100 10", FIELD(prob[FS_MOD_MOD]),              "mutation: probability of modifying a modifier",},
+				{"fS_mut_add_neuro",        0, 0, "Add neuron",                  "f 0 100 10", FIELD(prob[FS_ADD_NEURO]),            "mutation: probability of adding a neuron",},
+				{"fS_mut_rem_neuro",        0, 0, "Remove neuron",               "f 0 100 10", FIELD(prob[FS_REM_NEURO]),            "mutation: probability of removing a neuron",},
+				{"fS_mut_mod_neuro_conn",   0, 0, "Modify neuron connection",    "f 0 100 10", FIELD(prob[FS_MOD_NEURO_CONNECTION]), "mutation: probability of changing a neuron connection",},
+				{"fS_mut_add_neuro_conn",   0, 0, "Add neuron connection",       "f 0 100 10", FIELD(prob[FS_ADD_NEURO_CONNECTION]), "mutation: probability of adding a neuron connection",},
+				{"fS_mut_rem neuro_conn",   0, 0, "Remove neuron connection",    "f 0 100 10", FIELD(prob[FS_REM_NEURO_CONNECTION]), "mutation: probability of removing a neuron connection",},
+				{"fS_mut_mod_neuro_params", 0, 0, "Modify neuron params",        "f 0 100 10", FIELD(prob[FS_MOD_NEURO_PARAMS]),     "mutation: probability of changing a neuron param",},
+				{"fS_circle_section",       0, 0, "Ensure circle section",       "d 0 1 1",    FIELD(ensureCircleSection),           "Ensure that ellipsoids and cylinders have circle cross-section"},
+				{"fS_use_elli",             0, 0, "Use ellipsoids in mutations", "d 0 1 1",    FIELD(useElli),                       "Use ellipsoids in mutations"},
+				{"fS_use_cub",              0, 0, "Use cuboids in mutations",    "d 0 1 1",    FIELD(useCub),                        "Use cuboids in mutations"},
+				{"fS_use_cyl",              0, 0, "Use cylinders in mutations",  "d 0 1 1",    FIELD(useCyl),                        "Use cylinders in mutations"},
+				{"fS_mut_add_part_strong",  0, 0, "Strong add part mutation",    "d 0 1 1",    FIELD(strongAddPart),                 "Add part mutation will produce more parametrized parts"},
 		};
 
 #undef FIELDSTRUCT
+
+
+
+const std::map<string, double> minValues = {
+		{INGESTION,      0},//Model::getMinPart().ingest},
+		{FRICTION,       0},//Model::getMinPart().friction},
+		{STIFFNESS,	 	 0.1},
+		{ROT_X,          -M_PI},
+		{ROT_Y,          -M_PI},
+		{ROT_Z,          -M_PI},
+		{RX,             -M_PI},
+		{RY,             -M_PI},
+		{RZ,             -M_PI},
+		{SIZE,           0.01},
+		{SIZE_X,         0},//Model::getMinPart().scale.x},
+		{SIZE_Y,         0},//Model::getMinPart().scale.y},
+		{SIZE_Z,         0}//Model::getMinPart().scale.z}
+};
+
+const std::map<string, double> maxValues = {
+		{INGESTION,      1},//Model::getMaxPart().ingest},
+		{FRICTION,       1},//Model::getMaxPart().friction},
+		{STIFFNESS,	 	 0.5},
+		{ROT_X,          M_PI},
+		{ROT_Y,          M_PI},
+		{ROT_Z,          M_PI},
+		{RX,             M_PI},
+		{RY,             M_PI},
+		{RZ,             M_PI},
+		{SIZE,           100.0},
+		{SIZE_X,         1},//Model::getMaxPart().scale.x},
+		{SIZE_Y,         1},//Model::getMaxPart().scale.y},
+		{SIZE_Z,         1}//Model::getMaxPart().scale.z}
+};
+
 
 GenoOper_fS::GenoOper_fS()
@@ -49,7 +84,7 @@
 		fS_Genotype genotype(geno);
 		int errorPosition = genotype.checkValidityOfPartSizes();
-		if(errorPosition != 0)
-		{
-			logPrintf("GenoOper_fS", "checkValidity", LOG_ERROR, "Invalid part size");
+		if (errorPosition != 0)
+		{
+			logPrintf("GenoOper_fS", "checkValidity", LOG_WARN, "Invalid part size");
 			return errorPosition;
 		}
@@ -57,5 +92,5 @@
 	catch (fS_Exception &e)
 	{
-		logPrintf("GenoOper_fS", "checkValidity", LOG_ERROR, e.what());
+		logPrintf("GenoOper_fS", "checkValidity", LOG_WARN, e.what());
 		return 1 + e.errorPosition;
 	}
@@ -66,149 +101,165 @@
 int GenoOper_fS::mutate(char *&geno, float &chg, int &method)
 {
-	fS_Genotype genotype(geno);
-
-	// Calculate available part types
-	string availableTypes;
-	if(useElli)
-		availableTypes += ELLIPSOID;
-	if(useCub)
-		availableTypes += CUBOID;
-	if(useCyl)
-		availableTypes += CYLINDER;
-
-	// Select a mutation
-	bool result = false;
-	method = GenoOperators::roulette(prob, FS_OPCOUNT);
-	switch (method)
-	{
-		case FS_ADD_PART:
-			result = addPart(genotype, availableTypes);
-			break;
-		case FS_REM_PART:
-			result = removePart(genotype);
-			break;
-		case FS_MOD_PART:
-			result = changePartType(genotype, availableTypes);
-			break;
-		case FS_CHANGE_JOINT:
-			result = changeJoint(genotype);
-			break;
-		case FS_ADD_PARAM:
-			result = addParam(genotype);
-			break;
-		case FS_REM_PARAM:
-			result = removeParam(genotype);
-			break;
-		case FS_MOD_PARAM:
-			result = changeParam(genotype);
-			break;
-		case FS_MOD_MOD:
-			result = changeModifier(genotype);
-			break;
-		case FS_ADD_NEURO:
-			result = addNeuro(genotype);
-			break;
-		case FS_REM_NEURO:
-			result = removeNeuro(genotype);
-			break;
-		case FS_MOD_NEURO_CONNECTION:
-			result = changeNeuroConnection(genotype);
-			break;
-		case FS_ADD_NEURO_CONNECTION:
-			result = addNeuroConnection(genotype);
-			break;
-		case FS_REM_NEURO_CONNECTION:
-			result = removeNeuroConnection(genotype);
-			break;
-		case FS_MOD_NEURO_PARAMS:
-			result = changeNeuroParam(genotype);
-			break;
-	}
-
-	if (result)
-	{
-		free(geno);
-		geno = strdup(genotype.getGeno().c_str());
-		return GENOPER_OK;
-	}
-	return GENOPER_OPFAIL;
+	try
+	{
+		fS_Genotype genotype(geno);
+
+		// Calculate available part types
+		vector <Part::Shape> availablePartShapes;
+		if (useElli)
+			availablePartShapes.push_back(Part::Shape::SHAPE_ELLIPSOID);
+		if (useCub)
+			availablePartShapes.push_back(Part::Shape::SHAPE_CUBOID);
+		if (useCyl)
+			availablePartShapes.push_back(Part::Shape::SHAPE_CYLINDER);
+
+		// Select a mutation
+		bool result = false;
+		method = GenoOperators::roulette(prob, FS_OPCOUNT);
+		switch (method)
+		{
+			case FS_ADD_PART:
+				result = addPart(genotype, availablePartShapes);
+				break;
+			case FS_REM_PART:
+				result = removePart(genotype);
+				break;
+			case FS_MOD_PART:
+				result = changePartType(genotype, availablePartShapes);
+				break;
+			case FS_CHANGE_JOINT:
+				result = changeJoint(genotype);
+				break;
+			case FS_ADD_PARAM:
+				result = addParam(genotype);
+				break;
+			case FS_REM_PARAM:
+				result = removeParam(genotype);
+				break;
+			case FS_MOD_PARAM:
+				result = changeParam(genotype);
+				break;
+			case FS_MOD_MOD:
+				result = changeModifier(genotype);
+				break;
+			case FS_ADD_NEURO:
+				result = addNeuro(genotype);
+				break;
+			case FS_REM_NEURO:
+				result = removeNeuro(genotype);
+				break;
+			case FS_MOD_NEURO_CONNECTION:
+				result = changeNeuroConnection(genotype);
+				break;
+			case FS_ADD_NEURO_CONNECTION:
+				result = addNeuroConnection(genotype);
+				break;
+			case FS_REM_NEURO_CONNECTION:
+				result = removeNeuroConnection(genotype);
+				break;
+			case FS_MOD_NEURO_PARAMS:
+				result = changeNeuroParam(genotype);
+				break;
+		}
+
+		if (result)
+		{
+			free(geno);
+			geno = strdup(genotype.getGeno().c_str());
+			return GENOPER_OK;
+		}
+		return GENOPER_OPFAIL;
+	}
+	catch (fS_Exception &e)
+	{
+		logPrintf("GenoOper_fS", "mutate", LOG_WARN, e.what());
+		return GENOPER_OPFAIL;
+	}
 }
 
 int GenoOper_fS::crossOver(char *&g0, char *&g1, float &chg0, float &chg1)
 {
-	assert(PARENT_COUNT == 2); // Cross over works only for 2 parents
-	fS_Genotype *parents[PARENT_COUNT] = {new fS_Genotype(g0), new fS_Genotype(g1)};
-
-	// Choose random subtrees that have similar size
-	Node *selected[PARENT_COUNT];
-	vector<Node*> allNodes0 = parents[0]->getAllNodes();
-	vector<Node*> allNodes1 = parents[1]->getAllNodes();
-
-	double bestQuotient = DBL_MAX;
-	for (int i = 0; i < crossOverTries; i++)
-	{
-		Node *tmp0 = allNodes0[rndUint(allNodes0.size())];
-		Node *tmp1 = allNodes1[rndUint(allNodes1.size())];
-		// Choose this pair if it is the most similar
-		double quotient = double(tmp0->getNodeCount()) / double(tmp1->getNodeCount());
-		if(quotient < 1.0)
-			quotient = 1.0 / quotient;
-		if (quotient < bestQuotient)
-		{
-			bestQuotient = quotient;
-			selected[0] = tmp0;
-			selected[1] = tmp1;
-		}
-		if (bestQuotient == 1.0)
-			break;
-	}
-
-	// Compute gene percentages in children
-	double subtreeSizes[PARENT_COUNT], restSizes[PARENT_COUNT];
-	for (int i = 0; i < PARENT_COUNT; i++)
-	{
-
-		subtreeSizes[i] = selected[i]->getNodeCount();
-		restSizes[i] = parents[i]->getNodeCount() - subtreeSizes[i];
-	}
-	chg0 = restSizes[0] / (restSizes[0] + subtreeSizes[1]);
-	chg1 = restSizes[1] / (restSizes[1] + subtreeSizes[0]);
-
-	// Rearrange neurons before crossover
-	int subOldStart[PARENT_COUNT] {-1, -1};
-	rearrangeConnectionsBeforeCrossover(parents[0], selected[0], subOldStart[0]);
-	rearrangeConnectionsBeforeCrossover(parents[1], selected[1], subOldStart[1]);
-
-	// Swap the subtress
-	for(int i=0; i<PARENT_COUNT; i++)
-	{
-		Node *other = selected[1 - i];
-		Node *p = selected[i]->parent;
-		if (p != nullptr)
-		{
-			size_t index = std::distance(p->children.begin(), std::find(p->children.begin(), p->children.end(), selected[i]));
-			p->children[index] = other;
-		} else
-			parents[i]->startNode = other;
-	}
-
-	// Rearrange neurons after crossover
-	rearrangeConnectionsAfterCrossover(parents[0], selected[1], subOldStart[0]);
-	rearrangeConnectionsAfterCrossover(parents[1], selected[0], subOldStart[1]);
-
-	// Clenup, assign children to result strings
-	free(g0);
-	free(g1);
-	g0 = strdup(parents[0]->getGeno().c_str());
-	g1 = strdup(parents[1]->getGeno().c_str());
-
-	delete parents[0];
-	delete parents[1];
+	try
+	{
+		assert(PARENT_COUNT == 2); // Cross over works only for 2 parents
+		fS_Genotype *parents[PARENT_COUNT] = {new fS_Genotype(g0), new fS_Genotype(g1)};
+
+		// Choose random subtrees that have similar size
+		Node *selected[PARENT_COUNT];
+		vector < Node * > allNodes0 = parents[0]->getAllNodes();
+		vector < Node * > allNodes1 = parents[1]->getAllNodes();
+
+		double bestQuotient = DBL_MAX;
+		for (int i = 0; i < crossOverTries; i++)
+		{
+			Node *tmp0 = allNodes0[rndUint(allNodes0.size())];
+			Node *tmp1 = allNodes1[rndUint(allNodes1.size())];
+			// Choose this pair if it is the most similar
+			double quotient = double(tmp0->getNodeCount()) / double(tmp1->getNodeCount());
+			if (quotient < 1.0)
+				quotient = 1.0 / quotient;
+			if (quotient < bestQuotient)
+			{
+				bestQuotient = quotient;
+				selected[0] = tmp0;
+				selected[1] = tmp1;
+			}
+			if (bestQuotient == 1.0)
+				break;
+		}
+
+		// Compute gene percentages in children
+		double subtreeSizes[PARENT_COUNT], restSizes[PARENT_COUNT];
+		for (int i = 0; i < PARENT_COUNT; i++)
+		{
+
+			subtreeSizes[i] = selected[i]->getNodeCount();
+			restSizes[i] = parents[i]->getNodeCount() - subtreeSizes[i];
+		}
+		chg0 = restSizes[0] / (restSizes[0] + subtreeSizes[1]);
+		chg1 = restSizes[1] / (restSizes[1] + subtreeSizes[0]);
+
+		// Rearrange neurons before crossover
+		int subOldStart[PARENT_COUNT] {-1, -1};
+		rearrangeConnectionsBeforeCrossover(parents[0], selected[0], subOldStart[0]);
+		rearrangeConnectionsBeforeCrossover(parents[1], selected[1], subOldStart[1]);
+
+		// Swap the subtress
+		for (int i = 0; i < PARENT_COUNT; i++)
+		{
+			Node *other = selected[1 - i];
+			Node *p = selected[i]->parent;
+			if (p != nullptr)
+			{
+				size_t index = std::distance(p->children.begin(), std::find(p->children.begin(), p->children.end(), selected[i]));
+				p->children[index] = other;
+			} else
+				parents[i]->startNode = other;
+		}
+
+		// Rearrange neurons after crossover
+		rearrangeConnectionsAfterCrossover(parents[0], selected[1], subOldStart[0]);
+		rearrangeConnectionsAfterCrossover(parents[1], selected[0], subOldStart[1]);
+
+		// Clenup, assign children to result strings
+		free(g0);
+		free(g1);
+		g0 = strdup(parents[0]->getGeno().c_str());
+		g1 = strdup(parents[1]->getGeno().c_str());
+
+		delete parents[0];
+		delete parents[1];
+	}
+	catch (fS_Exception &e)
+	{
+		logPrintf("GenoOper_fS", "crossOver", LOG_WARN, e.what());
+		return GENOPER_OPFAIL;
+	}
 	return GENOPER_OK;
 }
 
-const char* GenoOper_fS::getSimplest()
-{
-	return "C{x=0.80599;y=0.80599;z=0.80599}";
+const char *GenoOper_fS::getSimplest()
+{
+	return "1.1:C{x=0.80599;y=0.80599;z=0.80599}";
 }
 
@@ -220,18 +271,14 @@
 	{
 		style = GENSTYLE_RGBS(0, 0, 200, GENSTYLE_BOLD);
-	}
-	else if(JOINTS.find(ch) != string::npos)	// Joint type
+	} else if (JOINTS.find(ch) != string::npos)    // Joint type
 	{
 		style = GENSTYLE_RGBS(0, 200, 200, GENSTYLE_BOLD);
-	}
-	else if(MODIFIERS.find(ch) != string::npos) // Modifier
+	} else if (MODIFIERS.find(ch) != string::npos) // Modifier
 	{
 		style = GENSTYLE_RGBS(0, 200, 0, GENSTYLE_NONE);
-	}
-	else if (isdigit(ch) || strchr(".", ch)) // Numerical value
+	} else if (isdigit(ch) || strchr(".", ch)) // Numerical value
 	{
 		style = GENSTYLE_RGBS(200, 0, 0, GENSTYLE_NONE);
-	}
-	else if(strchr("()_;[],=", ch))
+	} else if (strchr("()_;[],=", ch))
 	{
 		style = GENSTYLE_CS(0, GENSTYLE_BOLD); // Important char
@@ -243,6 +290,6 @@
 void GenoOper_fS::rearrangeConnectionsBeforeCrossover(fS_Genotype *geno, Node *sub, int &subStart)
 {
-	vector<fS_Neuron*> genoNeurons = geno->getAllNeurons();
-	vector<fS_Neuron*> subNeurons = fS_Genotype::extractNeurons(sub);
+	vector < fS_Neuron * > genoNeurons = geno->getAllNeurons();
+	vector < fS_Neuron * > subNeurons = fS_Genotype::extractNeurons(sub);
 
 	if (!subNeurons.empty())
@@ -255,6 +302,6 @@
 void GenoOper_fS::rearrangeConnectionsAfterCrossover(fS_Genotype *geno, Node *sub, int subOldStart)
 {
-	vector<fS_Neuron*> genoNeurons = geno->getAllNeurons();
-	vector<fS_Neuron*> subNeurons = fS_Genotype::extractNeurons(sub);
+	vector < fS_Neuron * > genoNeurons = geno->getAllNeurons();
+	vector < fS_Neuron * > subNeurons = fS_Genotype::extractNeurons(sub);
 
 	// Shift the inputs right
@@ -281,31 +328,29 @@
 }
 
-bool GenoOper_fS::addPart(fS_Genotype &geno, string availableTypes, bool mutateSize)
+bool GenoOper_fS::addPart(fS_Genotype &geno, const vector <Part::Shape> &availablePartShapes, bool mutateSize)
 {
 	geno.getState();
 	Node *node = geno.chooseNode();
-	char partType = availableTypes[rndUint(availableTypes.length())];
+	char partType = SHAPETYPE_TO_GENE.at(availablePartShapes[rndUint(availablePartShapes.size())]);
 
 	Substring substring(&partType, 0, 1);
-	Node *newNode = new Node(substring, node);
+	Node *newNode = new Node(substring, node, node->genotypeParams);
 	// Add random rotation
-	string rotationParams[]{ROT_X, ROT_Y, ROT_Z};
-	if(strongAddPart)
-	{
-		for(int i=0; i < 3; i++)
+	string rotationParams[] {ROT_X, ROT_Y, ROT_Z};
+	if (strongAddPart)
+	{
+		for (int i = 0; i < 3; i++)
 			newNode->params[rotationParams[i]] = RndGen.Uni(-M_PI / 2, M_PI / 2);
-	}
-	else
+	} else
 	{
 		string selectedParam = rotationParams[rndUint(3)];
 		newNode->params[selectedParam] = RndGen.Uni(-M_PI / 2, M_PI / 2);
 	}
-	string rParams[]{RX, RY, RZ};
-	if(strongAddPart)
-	{
-		for(int i=0; i < 3; i++)
+	string rParams[] {RX, RY, RZ};
+	if (strongAddPart)
+	{
+		for (int i = 0; i < 3; i++)
 			newNode->params[rParams[i]] = RndGen.Uni(-M_PI / 2, M_PI / 2);
-	}
-	else
+	} else
 	{
 		string selectedParam = rParams[rndUint(3)];
@@ -329,7 +374,7 @@
 	{
 		geno.getState();
-		newNode->changeSizeParam(SIZE_X, true);
-		newNode->changeSizeParam(SIZE_Y, true);
-		newNode->changeSizeParam(SIZE_Z, true);
+		newNode->mutateSizeParam(SIZE_X, true);
+		newNode->mutateSizeParam(SIZE_Y, true);
+		newNode->mutateSizeParam(SIZE_Z, true);
 	}
 	return true;
@@ -362,17 +407,14 @@
 }
 
-bool GenoOper_fS::changePartType(fS_Genotype &geno, string availTypes)
-{
-	int availTypesLength = availTypes.length();
+bool GenoOper_fS::changePartType(fS_Genotype &geno, const vector <Part::Shape> &availablePartShapes)
+{
+	int availShapesLen = availablePartShapes.size();
 	for (int i = 0; i < mutationTries; i++)
 	{
 		Node *randomNode = geno.chooseNode();
-		int index = rndUint(availTypesLength);
-		if (availTypes[index] == SHAPETYPE_TO_GENE.at(randomNode->partType))
-			index = (index + 1 + rndUint(availTypesLength - 1)) % availTypesLength;
-		char newTypeChr = availTypes[index];
-
-		auto itr = GENE_TO_SHAPETYPE.find(newTypeChr);
-		Part::Shape newType = itr->second;
+		int index = rndUint(availShapesLen);
+		if (availablePartShapes[index] == randomNode->partType)
+			index = (index + 1 + rndUint(availShapesLen - 1)) % availShapesLen;
+		Part::Shape newType = availablePartShapes[index];
 
 #ifdef _DEBUG
@@ -385,5 +427,5 @@
 		double relativeVolume = randomNode->calculateVolume() / pow(sizeMultiplier, 3.0);
 
-		if(!ensureCircleSection || newType == Part::Shape::SHAPE_CUBOID || (randomNode->partType == Part::Shape::SHAPE_ELLIPSOID && newType == Part::Shape::SHAPE_CYLINDER))
+		if (!ensureCircleSection || newType == Part::Shape::SHAPE_CUBOID || (randomNode->partType == Part::Shape::SHAPE_ELLIPSOID && newType == Part::Shape::SHAPE_CYLINDER))
 		{
 			double radiusQuotient = std::cbrt(volumeMultipliers.at(randomNode->partType) / volumeMultipliers.at(newType));
@@ -391,13 +433,11 @@
 			randomNode->params[SIZE_Y] = randomNode->getParam(SIZE_Y) * radiusQuotient;
 			randomNode->params[SIZE_Z] = randomNode->getParam(SIZE_Z) * radiusQuotient;
-		}
-		else if(randomNode->partType == Part::Shape::SHAPE_CUBOID && newType == Part::Shape::SHAPE_CYLINDER)
+		} else if (randomNode->partType == Part::Shape::SHAPE_CUBOID && newType == Part::Shape::SHAPE_CYLINDER)
 		{
 			double newRadius = 0.5 * (randomNode->getParam(SIZE_X) + randomNode->getParam(SIZE_Y));
-			randomNode->params[SIZE_X] = newRadius;
+			randomNode->params[SIZE_X] = 0.5 * relativeVolume / (M_PI * newRadius * newRadius);
 			randomNode->params[SIZE_Y] = newRadius;
-			randomNode->params[SIZE_Z] = 0.5 * relativeVolume / (M_PI * newRadius * newRadius);
-		}
-		else if(newType == Part::Shape::SHAPE_ELLIPSOID)
+			randomNode->params[SIZE_Z] = newRadius;
+		} else if (newType == Part::Shape::SHAPE_ELLIPSOID)
 		{
 			double newRelativeRadius = cbrt(relativeVolume / volumeMultipliers.at(newType));
@@ -405,6 +445,5 @@
 			randomNode->params[SIZE_Y] = newRelativeRadius;
 			randomNode->params[SIZE_Z] = newRelativeRadius;
-		}
-		else
+		} else
 		{
 			throw fS_Exception("Invalid part type", 1);
@@ -422,5 +461,5 @@
 
 	Node *randomNode = geno.chooseNode(1);        // First part does not have joints
-	int jointLen  = ALL_JOINTS.length();
+	int jointLen = ALL_JOINTS.length();
 	int index = rndUint(jointLen);
 	if (ALL_JOINTS[index] == randomNode->joint)
@@ -441,6 +480,6 @@
 		return false;
 	// Do not allow invalid changes in part size
-	bool isRadiusOfBase = key == SIZE_X || key == SIZE_Y;
-	bool isRadius = isRadiusOfBase || key == SIZE_Z;
+	bool isRadiusOfBase = key == SIZE_Y || key == SIZE_Z;
+	bool isRadius = isRadiusOfBase || key == SIZE_X;
 	if (ensureCircleSection && isRadius)
 	{
@@ -486,10 +525,10 @@
 
 			// Do not allow invalid changes in part size
-			if (it->first != SIZE_X && it->first != SIZE_Y && it->first != SIZE_Z)
+			if (std::find(SIZE_PARAMS.begin(), SIZE_PARAMS.end(), it->first) == SIZE_PARAMS.end())
 			{
 				it->second = GenoOperators::mutateCreep('f', it->second, minValues.at(it->first), maxValues.at(it->first), true);
 				return true;
 			} else
-				return randomNode->changeSizeParam(it->first, ensureCircleSection);
+				return randomNode->mutateSizeParam(it->first, ensureCircleSection);
 		}
 	}
@@ -516,6 +555,6 @@
 	Node *randomNode = geno.chooseNode();
 	fS_Neuron *newNeuron;
-	NeuroClass *rndclass = GenoOperators::getRandomNeuroClass(Model::SHAPE_SOLIDS);
-	if(rndclass->preflocation == 2 && randomNode == geno.startNode)
+	NeuroClass *rndclass = GenoOperators::getRandomNeuroClass(Model::SHAPETYPE_SOLIDS);
+	if (rndclass->preflocation == NeuroClass::PREFER_JOINT && randomNode == geno.startNode)
 		return false;
 
@@ -526,5 +565,5 @@
 	{
 		// Create as many connections for the neuron as possible (at most prefinputs)
-		vector<fS_Neuron*> allNeurons = geno.getAllNeurons();
+		vector < fS_Neuron * > allNeurons = geno.getAllNeurons();
 		vector<int> neuronsWithOutput;
 		for (int i = 0; i < int(allNeurons.size()); i++)
@@ -574,5 +613,5 @@
 bool GenoOper_fS::changeNeuroConnection(fS_Genotype &geno)
 {
-	vector<fS_Neuron*> neurons = geno.getAllNeurons();
+	vector < fS_Neuron * > neurons = geno.getAllNeurons();
 	if (neurons.empty())
 		return false;
@@ -597,5 +636,5 @@
 bool GenoOper_fS::addNeuroConnection(fS_Genotype &geno)
 {
-	vector<fS_Neuron*> neurons = geno.getAllNeurons();
+	vector < fS_Neuron * > neurons = geno.getAllNeurons();
 	if (neurons.empty())
 		return false;
@@ -627,5 +666,5 @@
 bool GenoOper_fS::removeNeuroConnection(fS_Genotype &geno)
 {
-	vector<fS_Neuron*> neurons = geno.getAllNeurons();
+	vector < fS_Neuron * > neurons = geno.getAllNeurons();
 	if (neurons.empty())
 		return false;
@@ -649,5 +688,5 @@
 bool GenoOper_fS::changeNeuroParam(fS_Genotype &geno)
 {
-	vector<fS_Neuron*> neurons = geno.getAllNeurons();
+	vector < fS_Neuron * > neurons = geno.getAllNeurons();
 	if (neurons.empty())
 		return false;
@@ -656,2 +695,32 @@
 	return GenoOperators::mutateRandomNeuroClassProperty(neu);
 }
+
+bool Node::mutateSizeParam(string key, bool ensureCircleSection)
+{
+	double oldValue = getParam(key);
+	double volume = calculateVolume();
+	double valueAtMinVolume, valueAtMaxVolume;
+	if(key == SIZE)
+	{
+		valueAtMinVolume = oldValue * std::cbrt(Model::getMinPart().volume / volume);
+		valueAtMaxVolume = oldValue * std::cbrt(Model::getMaxPart().volume / volume);
+	}
+	else
+	{
+		valueAtMinVolume = oldValue * Model::getMinPart().volume / volume;
+		valueAtMaxVolume = oldValue * Model::getMaxPart().volume / volume;
+	}
+
+	double min = std::max(minValues.at(key), valueAtMinVolume);
+	double max = std::min(maxValues.at(key), valueAtMaxVolume);
+
+	params[key] = GenoOperators::mutateCreep('f', getParam(key), min, max, true);
+
+	if (!ensureCircleSection || isPartSizeValid())
+		return true;
+	else
+	{
+		params[key] = oldValue;
+		return false;
+	}
+}
Index: /cpp/frams/genetics/fS/fS_oper.h
===================================================================
--- /cpp/frams/genetics/fS/fS_oper.h	(revision 999)
+++ /cpp/frams/genetics/fS/fS_oper.h	(revision 1000)
@@ -74,5 +74,5 @@
 	 * @return true if mutation succeeded, false otherwise
 	 */
-	bool addPart(fS_Genotype &geno, string availableTypes = "ECR", bool mutateSize = true);
+	bool addPart(fS_Genotype &geno, const vector<Part::Shape> &availablePartShapes, bool mutateSize = true);
 
 	/**
@@ -86,5 +86,5 @@
 	 * @return true if mutation succeeded, false otherwise
 	 */
-	bool changePartType(fS_Genotype &geno, string availableTypes = "ECR");
+	bool changePartType(fS_Genotype &geno, const vector<Part::Shape> &availablePartShapes);
 
 	/**
