Index: cpp/frams/genetics/fS/fS_general.cpp
===================================================================
--- cpp/frams/genetics/fS/fS_general.cpp	(revision 1031)
+++ cpp/frams/genetics/fS/fS_general.cpp	(revision 1032)
@@ -12,5 +12,5 @@
 #include "../genooperators.h"
 #include "common/nonstd_math.h"
-#include "part_distance_estimator.h"
+#include "../../model/geometry/part_distance_estimator.h"
 
 int fS_Genotype::precision = 4;
@@ -81,9 +81,9 @@
 		return std::stod(str, size);
 	}
-	catch(const std::invalid_argument& ex)
+	catch(const std::invalid_argument&)
 	{
 		throw fS_Exception("Invalid numeric value", start);
 	}
-	catch(const std::out_of_range& ex)
+	catch(const std::out_of_range&)
 	{
 		throw fS_Exception("Invalid numeric value; out of range", start);
@@ -123,4 +123,14 @@
 }
 
+int findEndOfNeuronParamString(SString neuronDefinition)
+{
+	for(int i=1; i< neuronDefinition.size(); i++)
+	{
+		if(neuronDefinition[i - 1] == ',' && isdigit(neuronDefinition[i]))
+			return i - 1;
+	}
+
+	return neuronDefinition.size();
+}
 
 fS_Neuron::fS_Neuron(const char *str, int _start, int length)
@@ -131,13 +141,12 @@
 		return;
 
-	vector<SString> inputStrings;
-	strSplit(SString(str, length), NEURON_INTERNAL_SEPARATOR, false, inputStrings);
-	if (inputStrings.empty())
-		return;
-
-	int inputStart = 0;
+	SString neuronDefinition(str, length);
+	int endOfNeuronParamString = findEndOfNeuronParamString(neuronDefinition);
+	SString neuronParamString = neuronDefinition.substr(0, endOfNeuronParamString);
+	SString neuronInputString = neuronDefinition.substr(endOfNeuronParamString + 1);
+
 	SString details = "N";
 
-	SString tmp = inputStrings[0];
+	SString tmp = neuronParamString;
 	if(tmp.indexOf(':') != -1)
 		tmp = tmp.substr(0, tmp.indexOf(':'));
@@ -145,10 +154,16 @@
 	if (NeuroLibrary::staticlibrary.findClassIndex(tmp, true) != -1)
 	{
-		inputStart = 1;
-		details = inputStrings[0];
+		details = neuronParamString;
+	}
+	else{
+		neuronInputString = neuronParamString;
 	}
 	setDetails(details);
 
-	for (int i = inputStart; i < int(inputStrings.size()); i++)
+	vector<SString> inputStrings;
+	strSplit(neuronInputString, NEURON_INTERNAL_SEPARATOR, false, inputStrings);
+	if (inputStrings.empty() || inputStrings[0] == SString())
+		return;
+	for (int i = 0; i < int(inputStrings.size()); i++)
 	{
 		SString keyValue = inputStrings[i];
@@ -421,4 +436,5 @@
 	char c;
 	const char *str = restOfGenotype.c_str();
+	bool insideSpecifiation = false;	// True when inside parameter or neuron specification
 	for (int i = 0; i < restOfGenotype.len; i++)
 	{
@@ -428,5 +444,9 @@
 		if (c == BRANCH_START)
 			depth++;
-		else if ((c == BRANCH_SEPARATOR && depth == 1) || i + 1 == restOfGenotype.len)
+		else if (c == PARAM_START || c == NEURON_START)
+			insideSpecifiation = true;
+		else if (c == PARAM_END || c == NEURON_END)
+			insideSpecifiation = false;
+		else if (!insideSpecifiation && ((c == BRANCH_SEPARATOR && depth == 1) || i + 1 == restOfGenotype.len))
 		{
 			Substring substring(restOfGenotype);
@@ -453,47 +473,14 @@
 double Node::calculateVolume()
 {
-	double result;
+	Part *tmpPart = new Part(partShape);
+	calculateScale(tmpPart->scale);
+	return GeometryUtils::calculateSolidVolume(tmpPart);
+}
+
+bool Node::isPartScaleValid()
+{
 	Pt3D scale;
 	calculateScale(scale);
-	double radiiProduct = scale.x * scale.y * scale.z;
-	switch (partShape)
-	{
-		case Part::Shape::SHAPE_CUBOID:
-			result = 8.0 * radiiProduct;
-			break;
-		case Part::Shape::SHAPE_CYLINDER:
-			result = 2.0 * M_PI * radiiProduct;
-			break;
-		case Part::Shape::SHAPE_ELLIPSOID:
-			result = (4.0 / 3.0) * M_PI * radiiProduct;
-			break;
-		default:
-			logMessage("fS", "calculateVolume", LOG_ERROR, "Invalid part type");
-	}
-	return result;
-}
-
-bool Node::isPartScaleValid()
-{
-	Pt3D scale;
-	calculateScale(scale);
-	double volume = calculateVolume();
-	Part_MinMaxDef minP = Model::getMinPart();
-	Part_MinMaxDef maxP = Model::getMaxPart();
-
-	if (volume > maxP.volume || minP.volume > volume)
-		return false;
-	if (scale.x < minP.scale.x || scale.y < minP.scale.y || scale.z < minP.scale.z)
-		return false;
-	if (scale.x > maxP.scale.x || scale.y > maxP.scale.y || scale.z > maxP.scale.z)
-		return false;
-
-	if (partShape == Part::Shape::SHAPE_ELLIPSOID && scale.maxComponentValue() != scale.minComponentValue())
-		// When not all radii have different values
-		return false;
-	if (partShape == Part::Shape::SHAPE_CYLINDER && scale.y != scale.z)
-		// If base radii have different values
-		return false;
-	return true;
+	return GeometryUtils::isSolidPartScaleValid(partShape, scale);
 }
 
@@ -663,9 +650,6 @@
 }
 
-fS_Genotype::fS_Genotype(const string &g)
-{
-	string geno(g);
-	geno.erase(remove(geno.begin(), geno.end(), ' '), geno.end());
-	geno.erase(remove(geno.begin(), geno.end(), '\n'), geno.end());
+fS_Genotype::fS_Genotype(const string &geno)
+{
 	try
 	{
@@ -708,9 +692,4 @@
 		delete startNode;
 		throw e;
-	}
-	catch(...)
-	{
-		delete startNode;
-		throw fS_Exception("Unknown exception in fS", 0);
 	}
 }
@@ -789,5 +768,5 @@
 	geno += doubleToString(gp.modifierMultiplier, precision).c_str();
 	geno += ",";
-	geno += doubleToString(gp.turnWithRotation, precision).c_str();
+	geno += std::to_string(int(gp.turnWithRotation)).c_str();
 	geno += ",";
 	geno += doubleToString(gp.paramMutationStrength, precision).c_str();
@@ -932,13 +911,7 @@
 
 	double result;
-	try
-	{
-		tmpPart->p = state->v;
-		result = PartDistanceEstimator::calculateDistance(*tmpPart, *parentTmpPart, genotypeParams.distanceTolerance, genotypeParams.relativeDensity);
-	}
-	catch (...)
-	{
-		throw fS_Exception("Exception thrown while calculating distance from parent", 0);
-	}
+	tmpPart->p = state->v;
+	result = PartDistanceEstimator::calculateDistance(*tmpPart, *parentTmpPart, genotypeParams.distanceTolerance, genotypeParams.relativeDensity);
+
 
 	delete tmpPart;
Index: cpp/frams/genetics/fS/fS_general.h
===================================================================
--- cpp/frams/genetics/fS/fS_general.h	(revision 1031)
+++ cpp/frams/genetics/fS/fS_general.h	(revision 1032)
@@ -19,13 +19,13 @@
 #define BRANCH_START '('
 #define BRANCH_END ')'
-#define BRANCH_SEPARATOR '^'
+#define BRANCH_SEPARATOR ','
 #define PARAM_START '{'
 #define PARAM_END '}'
-const char PARAM_SEPARATOR = ';';
+const char PARAM_SEPARATOR = ',';
 const char PARAM_KEY_VALUE_SEPARATOR = '=';
 #define NEURON_START '['
 const char NEURON_END = ']';
 const char NEURON_SEPARATOR = ';';
-const SString NEURON_INTERNAL_SEPARATOR("'");
+const SString NEURON_INTERNAL_SEPARATOR(",");
 #define NEURON_I_W_SEPARATOR ':'
 //@}
@@ -274,4 +274,5 @@
 	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
+
 	static std::map<string, double> minValues;	/// Min parameter values
 	static std::map<string, double> defaultValues;	/// Default parameter values
Index: cpp/frams/genetics/fS/fS_oper.cpp
===================================================================
--- cpp/frams/genetics/fS/fS_oper.cpp	(revision 1031)
+++ cpp/frams/genetics/fS/fS_oper.cpp	(revision 1032)
@@ -226,5 +226,5 @@
 const char *GenoOper_fS::getSimplest()
 {
-	return "1.1,0,0.4:C{x=0.80599;y=0.80599;z=0.80599}";
+	return "1.1,0,0.4:C{x=0.80599,y=0.80599,z=0.80599}";
 }
 
Index: cpp/frams/genetics/fS/part_distance_estimator.h
===================================================================
--- cpp/frams/genetics/fS/part_distance_estimator.h	(revision 1031)
+++ 	(revision )
@@ -1,91 +1,0 @@
-// This file is a part of Framsticks SDK.  http://www.framsticks.com/
-// Copyright (C) 2019-2020  Maciej Komosinski and Szymon Ulatowski.
-// See LICENSE.txt for details.
-
-#ifndef _PART_DISTANCE_ESTIMATOR_H_
-#define _PART_DISTANCE_ESTIMATOR_H_
-
-#include "frams/model/geometry/meshbuilder.h"
-
-class PartDistanceEstimator
-{
-public:
-
-	static Part *buildTemporaryPart(Part::Shape shape, const Pt3D &scale, const Pt3D &rotation)
-	{
-		Part *tmpPart1 = new Part(shape);
-		tmpPart1->scale = scale;
-		tmpPart1->setRot(rotation);
-		return tmpPart1;
-	}
-
-	/// Get some of the points from the surface of the part
-	static vector <Pt3D> findSurfacePoints(Part *part, double  relativeDensity)
-	{
-		// Divide by maximal radius to avoid long computations
-		MeshBuilder::PartSurface surface(relativeDensity / part->scale.maxComponentValue());
-		surface.initialize(part);
-
-		vector <Pt3D> points;
-		Pt3D point;
-		while (surface.tryGetNext(point))
-		{
-			points.push_back(point);
-		}
-		return points;
-	}
-
-	/// Check if there is a collision between the parts
-	static bool isCollision(Part *part, vector <Pt3D> &points, Pt3D &vectorBetweenParts)
-	{
-		static double CBRT_3 = std::cbrt(3);
-		double maxPartReachSq = pow(CBRT_3 * part->scale.maxComponentValue(), 2);
-		for (int i = 0; i < int(points.size()); i++)
-		{
-			Pt3D shifted = points[i] + vectorBetweenParts;
-			double distanceToPointSq = shifted.x * shifted.x + shifted.y * shifted.y + shifted.z * shifted.z;
-			if (distanceToPointSq <= maxPartReachSq && GeometryUtils::isPointInsidePart(shifted, part))
-				return true;
-		}
-		return false;
-	}
-
-
-	static double calculateDistance(Part tmpPart1, Part tmpPart2, double distanceTolerance, double relativeDensity)
-	{
-		/// tmpPart1 and tmpPart2 are copied for purpose and should not be passed as reference
-		/// This function can change some of the properties of those parts
-		Pt3D directionVersor = tmpPart1.p - tmpPart2.p;
-		directionVersor.normalize();
-
-		tmpPart1.p = Pt3D(0);
-		tmpPart2.p = Pt3D(0);
-
-		static double CBRT_3 = std::cbrt(3);
-		vector <Pt3D> points = PartDistanceEstimator::findSurfacePoints(&tmpPart1, relativeDensity);
-
-		double minDistance = tmpPart2.scale.minComponentValue() + tmpPart1.scale.minComponentValue();
-		double maxDistance = CBRT_3 * (tmpPart2.scale.maxComponentValue() + tmpPart1.scale.maxComponentValue());
-		double currentDistance = 0.5 * (maxDistance + minDistance);
-		int collisionDetected = false;
-		while (maxDistance - minDistance > distanceTolerance)
-		{
-			Pt3D vectorBetweenParts = directionVersor * currentDistance;
-			collisionDetected = PartDistanceEstimator::isCollision(&tmpPart2, points, vectorBetweenParts);
-
-			if (collisionDetected)
-			{
-				minDistance = currentDistance;
-				currentDistance = 0.5 * (maxDistance + currentDistance);
-			} else
-			{
-				maxDistance = currentDistance;
-				currentDistance = 0.5 * (currentDistance + minDistance);
-			}
-		}
-		return currentDistance;
-	}
-};
-
-
-#endif //_PART_DISTANCE_ESTIMATOR_H_
Index: cpp/frams/genetics/genooperators.cpp
===================================================================
--- cpp/frams/genetics/genooperators.cpp	(revision 1031)
+++ cpp/frams/genetics/genooperators.cpp	(revision 1032)
@@ -455,19 +455,2 @@
 	return isupper(firstchar) || firstchar == '|' || firstchar == '@' || firstchar == '*';
 }
-
-double GenoOperators::calculateSolidVolume(Part * part)
-{
-	double radiiProduct = part->scale.x * part->scale.y * part->scale.z;
-	switch (part->shape)
-	{
-	case Part::Shape::SHAPE_CUBOID:
-		return 8.0 * radiiProduct;
-	case Part::Shape::SHAPE_CYLINDER:
-		return  2.0 * M_PI * radiiProduct;
-	case Part::Shape::SHAPE_ELLIPSOID:
-		return  (4.0 / 3.0) * M_PI * radiiProduct;
-	default:
-		logMessage("GenoOperators", "calculateSolidVolume", LOG_ERROR, "Unsupported part shape");
-		return -1;
-	}
-}
Index: cpp/frams/genetics/genooperators.h
===================================================================
--- cpp/frams/genetics/genooperators.h	(revision 1031)
+++ cpp/frams/genetics/genooperators.h	(revision 1032)
@@ -215,5 +215,4 @@
 	static bool canStartNeuroClassName(const char firstchar); ///<determines if \e firstchar may start NeuroClass name. If not, it might start NeuroClass' (or Neuro's) property name.
 
-	static double calculateSolidVolume(Part *part);
 
 	//@}
Index: cpp/frams/model/geometry/geometryutils.cpp
===================================================================
--- cpp/frams/model/geometry/geometryutils.cpp	(revision 1031)
+++ cpp/frams/model/geometry/geometryutils.cpp	(revision 1032)
@@ -1,4 +1,4 @@
 // This file is a part of Framsticks SDK.  http://www.framsticks.com/
-// Copyright (C) 1999-2015  Maciej Komosinski and Szymon Ulatowski.
+// Copyright (C) 1999-2020  Maciej Komosinski and Szymon Ulatowski.
 // See LICENSE.txt for details.
 
@@ -369,2 +369,42 @@
 	return M_PI * ((3 * (a+b)) - sqrt((3*a + b) * (a + 3*b)));
 }
+
+double GeometryUtils::calculateSolidVolume(Part * part)
+{
+	double radiiProduct = part->scale.x * part->scale.y * part->scale.z;
+	switch (part->shape)
+	{
+		case Part::Shape::SHAPE_CUBOID:
+			return 8.0 * radiiProduct;
+		case Part::Shape::SHAPE_CYLINDER:
+			return  2.0 * M_PI * radiiProduct;
+		case Part::Shape::SHAPE_ELLIPSOID:
+			return  (4.0 / 3.0) * M_PI * radiiProduct;
+		default:
+			logMessage("GeometryUtils", "calculateSolidVolume", LOG_ERROR, "Unsupported part shape");
+			return -1;
+	}
+}
+
+bool GeometryUtils::isSolidPartScaleValid(const Part::Shape &partShape, const Pt3D &scale)
+{
+	Part *tmpPart = new Part(partShape);
+	tmpPart->scale = scale;
+	double volume = GeometryUtils::calculateSolidVolume(tmpPart);
+
+	Part_MinMaxDef minP = Model::getMinPart();
+	Part_MinMaxDef maxP = Model::getMaxPart();
+
+	if (volume > maxP.volume || minP.volume > volume)
+		return false;
+	if (scale.x < minP.scale.x || scale.y < minP.scale.y || scale.z < minP.scale.z)
+		return false;
+	if (scale.x > maxP.scale.x || scale.y > maxP.scale.y || scale.z > maxP.scale.z)
+		return false;
+
+	if (partShape == Part::Shape::SHAPE_ELLIPSOID && scale.maxComponentValue() != scale.minComponentValue()) // When any radius has a different value than the others
+		return false;
+	if (partShape == Part::Shape::SHAPE_CYLINDER && scale.y != scale.z) // If base radii have different values
+		return false;
+	return true;
+}
Index: cpp/frams/model/geometry/geometryutils.h
===================================================================
--- cpp/frams/model/geometry/geometryutils.h	(revision 1031)
+++ cpp/frams/model/geometry/geometryutils.h	(revision 1032)
@@ -1,4 +1,4 @@
 // This file is a part of Framsticks SDK.  http://www.framsticks.com/
-// Copyright (C) 1999-2015  Maciej Komosinski and Szymon Ulatowski.
+// Copyright (C) 1999-2020  Maciej Komosinski and Szymon Ulatowski.
 // See LICENSE.txt for details.
 
@@ -177,4 +177,7 @@
 	double ellipsoidArea(const double a, const double b, const double c);
 	double ellipsePerimeter(const double a, const double b);
+
+	double calculateSolidVolume(Part *part);
+	bool isSolidPartScaleValid(const Part::Shape &partShape, const Pt3D &scale);
 }
 
Index: cpp/frams/model/geometry/part_distance_estimator.h
===================================================================
--- cpp/frams/model/geometry/part_distance_estimator.h	(revision 1032)
+++ cpp/frams/model/geometry/part_distance_estimator.h	(revision 1032)
@@ -0,0 +1,94 @@
+// This file is a part of Framsticks SDK.  http://www.framsticks.com/
+// Copyright (C) 2019-2020  Maciej Komosinski and Szymon Ulatowski.
+// See LICENSE.txt for details.
+
+#ifndef _PART_DISTANCE_ESTIMATOR_H_
+#define _PART_DISTANCE_ESTIMATOR_H_
+
+#include "frams/model/geometry/meshbuilder.h"
+
+class PartDistanceEstimator
+{
+public:
+
+	static Part *buildTemporaryPart(Part::Shape shape, const Pt3D &scale, const Pt3D &rotation)
+	{
+		Part *tmpPart1 = new Part(shape);
+		tmpPart1->scale = scale;
+		tmpPart1->setRot(rotation);
+		return tmpPart1;
+	}
+
+	/// Get some of the points from the surface of the part
+	static vector <Pt3D> findSurfacePoints(Part *part, double  relativeDensity)
+	{
+		// Divide by maximal radius to avoid long computations
+		MeshBuilder::PartSurface surface(relativeDensity / part->scale.maxComponentValue());
+		surface.initialize(part);
+
+		vector <Pt3D> points;
+		Pt3D point;
+		while (surface.tryGetNext(point))
+		{
+			points.push_back(point);
+		}
+		return points;
+	}
+
+	/// Check if there is a collision between the parts
+	static bool isCollision(Part *part, vector <Pt3D> &points, Pt3D &vectorBetweenParts)
+	{
+		static double CBRT_3 = std::cbrt(3);
+		double maxPartReachSq = pow(CBRT_3 * part->scale.maxComponentValue(), 2);
+		for (int i = 0; i < int(points.size()); i++)
+		{
+			Pt3D shifted = points[i] + vectorBetweenParts;
+			double distanceToPointSq = shifted.x * shifted.x + shifted.y * shifted.y + shifted.z * shifted.z;
+			if (distanceToPointSq <= maxPartReachSq && GeometryUtils::isPointInsidePart(shifted, part))
+				return true;
+		}
+		return false;
+	}
+
+
+	static double calculateDistance(Part tmpPart1, Part tmpPart2, double distanceTolerance, double relativeDensity)
+	{
+		/// tmpPart1 and tmpPart2 are copied for purpose and should not be passed as reference
+		/// This function can change some of the properties of those parts
+		/// tmpPart1 will be approximated by surface points.
+		/// The collision between the parts is detected when any of those points is inside tmpPart2
+		/// If tmpPart1 and tmpPart2 are swapped, the calculated distance may slightly differ
+		Pt3D directionVersor = tmpPart1.p - tmpPart2.p;
+		directionVersor.normalize();
+
+		tmpPart1.p = Pt3D_0;
+		tmpPart2.p = Pt3D_0;
+
+		static double CBRT_3 = std::cbrt(3);
+		vector <Pt3D> points = PartDistanceEstimator::findSurfacePoints(&tmpPart1, relativeDensity);
+
+		double minDistance = tmpPart2.scale.minComponentValue() + tmpPart1.scale.minComponentValue();
+		double maxDistance = CBRT_3 * (tmpPart2.scale.maxComponentValue() + tmpPart1.scale.maxComponentValue());
+		double currentDistance = 0.5 * (maxDistance + minDistance);
+		int collisionDetected = false;
+		while (maxDistance - minDistance > distanceTolerance)
+		{
+			Pt3D vectorBetweenParts = directionVersor * currentDistance;
+			collisionDetected = PartDistanceEstimator::isCollision(&tmpPart2, points, vectorBetweenParts);
+
+			if (collisionDetected)
+			{
+				minDistance = currentDistance;
+				currentDistance = 0.5 * (maxDistance + currentDistance);
+			} else
+			{
+				maxDistance = currentDistance;
+				currentDistance = 0.5 * (currentDistance + minDistance);
+			}
+		}
+		return currentDistance;
+	}
+};
+
+
+#endif //_PART_DISTANCE_ESTIMATOR_H_
