diff --git a/auto/Wrap/doxygenCore.i b/auto/Wrap/doxygenCore.i
index 329624469ec31800eb733b4527c1d8aafa904217..dd87aa3d41566fb5a33a97a76f65fcfe399a7287 100644
--- a/auto/Wrap/doxygenCore.i
+++ b/auto/Wrap/doxygenCore.i
@@ -1466,6 +1466,43 @@ weight_factors:
 user-defined weighting factors. Used linearly, no matter which norm is chosen. 
 ";
 
+%feature("docstring")  PoissonLikeMetric::computeFromArrays "double Chi2Metric::computeFromArrays(std::vector< double > sim_data, std::vector< double > exp_data, std::vector< double > uncertainties, std::vector< double > weight_factors) const override
+
+Computes metric value from data arrays. Negative values in exp_data are ignored as well as non-positive weight_factors and uncertainties. All arrays involved in the computation must be of the same size.
+
+Parameters:
+-----------
+
+sim_data: 
+array with simulated intensities.
+
+exp_data: 
+array with intensity values obtained from an experiment.
+
+uncertainties: 
+array with experimental data uncertainties.
+
+weight_factors: 
+user-defined weighting factors. Used linearly, no matter which norm is chosen. 
+";
+
+%feature("docstring")  PoissonLikeMetric::computeFromArrays "double Chi2Metric::computeFromArrays(std::vector< double > sim_data, std::vector< double > exp_data, std::vector< double > weight_factors) const override
+
+Computes metric value from data arrays. Negative values in exp_data are ignored as well as non-positive weight_factors. All arrays involved in the computation must be of the same size.
+
+Parameters:
+-----------
+
+sim_data: 
+array with simulated intensities.
+
+exp_data: 
+array with intensity values obtained from an experiment.
+
+weight_factors: 
+user-defined weighting factors. Used linearly, no matter which norm is chosen. 
+";
+
 
 // File: classPoissonNoiseBackground.xml
 %feature("docstring") PoissonNoiseBackground "
@@ -1639,6 +1676,43 @@ weight_factors:
 user-defined weighting factors. Used linearly, no matter which norm is chosen. 
 ";
 
+%feature("docstring")  RelativeDifferenceMetric::computeFromArrays "double Chi2Metric::computeFromArrays(std::vector< double > sim_data, std::vector< double > exp_data, std::vector< double > uncertainties, std::vector< double > weight_factors) const override
+
+Computes metric value from data arrays. Negative values in exp_data are ignored as well as non-positive weight_factors and uncertainties. All arrays involved in the computation must be of the same size.
+
+Parameters:
+-----------
+
+sim_data: 
+array with simulated intensities.
+
+exp_data: 
+array with intensity values obtained from an experiment.
+
+uncertainties: 
+array with experimental data uncertainties.
+
+weight_factors: 
+user-defined weighting factors. Used linearly, no matter which norm is chosen. 
+";
+
+%feature("docstring")  RelativeDifferenceMetric::computeFromArrays "double Chi2Metric::computeFromArrays(std::vector< double > sim_data, std::vector< double > exp_data, std::vector< double > weight_factors) const override
+
+Computes metric value from data arrays. Negative values in exp_data are ignored as well as non-positive weight_factors. All arrays involved in the computation must be of the same size.
+
+Parameters:
+-----------
+
+sim_data: 
+array with simulated intensities.
+
+exp_data: 
+array with intensity values obtained from an experiment.
+
+weight_factors: 
+user-defined weighting factors. Used linearly, no matter which norm is chosen. 
+";
+
 
 // File: classRoughMultiLayerComputation.xml
 %feature("docstring") RoughMultiLayerComputation "
@@ -2235,49 +2309,49 @@ Returns default units to convert to.
 ";
 
 
-// File: namespace_0D15.xml
+// File: namespace_0d15.xml
 
 
-// File: namespace_0D19.xml
+// File: namespace_0d19.xml
 
 
-// File: namespace_0D27.xml
+// File: namespace_0d27.xml
 
 
-// File: namespace_0D35.xml
+// File: namespace_0d36.xml
 
 
-// File: namespace_0D40.xml
+// File: namespace_0d41.xml
 
 
-// File: namespace_0D49.xml
+// File: namespace_0d50.xml
 
 
-// File: namespace_0D51.xml
+// File: namespace_0d52.xml
 
 
-// File: namespace_0D55.xml
+// File: namespace_0d56.xml
 
 
-// File: namespace_0D57.xml
+// File: namespace_0d58.xml
 
 
-// File: namespace_0D62.xml
+// File: namespace_0d63.xml
 
 
-// File: namespace_0D64.xml
+// File: namespace_0d65.xml
 
 
-// File: namespace_0D68.xml
+// File: namespace_0d69.xml
 
 
-// File: namespace_0D78.xml
+// File: namespace_0d79.xml
 
 
-// File: namespace_0D80.xml
+// File: namespace_0d81.xml
 
 
-// File: namespace_0D86.xml
+// File: namespace_0d87.xml
 
 
 // File: namespaceExportToPython.xml
@@ -2352,6 +2426,31 @@ Returns default metric name.
 ";
 
 
+// File: namespacepyfmt2.xml
+%feature("docstring")  pyfmt2::representShape2D "std::string pyfmt2::representShape2D(const std::string &indent, const IShape2D *ishape, bool mask_value, std::function< std::string(double)> printValueFunc)
+
+Returns fixed Python code snippet that defines the function \"runSimulation\". 
+";
+
+%feature("docstring")  pyfmt2::valueTimesUnit "std::string pyfmt2::valueTimesUnit(const RealParameter *par)
+
+Returns parameter value, followed by its unit multiplicator (like \"* nm\"). 
+";
+
+%feature("docstring")  pyfmt2::argumentList "std::string pyfmt2::argumentList(const IParameterized *ip)
+
+Returns comma-separated list of parameter values, including unit multiplicator (like \"* nm\"). 
+";
+
+%feature("docstring")  pyfmt2::printDistribution "std::string pyfmt2::printDistribution(const IDistribution1D &par_distr, const std::string &units)
+
+Prints distribution with constructor parameters in given units. ba.DistributionGaussian(2.0*deg, 0.02*deg) 
+";
+
+%feature("docstring")  pyfmt2::printParameterDistribution "std::string pyfmt2::printParameterDistribution(const ParameterDistribution &par_distr, const std::string &distVarName, const std::string &units)
+";
+
+
 // File: namespaceStandardSimulations.xml
 %feature("docstring")  StandardSimulations::BasicGISAS "GISASSimulation * StandardSimulations::BasicGISAS()
 
@@ -2643,6 +2742,9 @@ Helper factory function to use in  GISASSimulation. Depending on the type of det
 // File: OrderedMap_8h.xml
 
 
+// File: PyFmt2_8cpp.xml
+
+
 // File: SampleLabelHandler_8cpp.xml
 
 
diff --git a/auto/Wrap/doxygenSample.i b/auto/Wrap/doxygenSample.i
index 82e19d701f29bc862f66e961b5168a93f01ec6fa..e2ef874b1004f9abe119edd3f480ffcb426193ca 100644
--- a/auto/Wrap/doxygenSample.i
+++ b/auto/Wrap/doxygenSample.i
@@ -5040,7 +5040,7 @@ Returns lateral correlation length.
 // File: classLayersWithAbsorptionBuilder.xml
 %feature("docstring") LayersWithAbsorptionBuilder "
 
-The  LayersWithAbsorptionBuilder class generates a multilayer with 3 layers with absorption (refractive index has imaginary part).The middle layer is populated with particles. Requires IComponentService which generates form factors, used for bulk form factors testing.
+The  LayersWithAbsorptionBuilder class generates a multilayer with 3 layers with absorption (refractive index has imaginary part). The middle layer is populated with particles. Requires IComponentService which generates form factors, used for bulk form factors testing.
 
 C++ includes: LayersWithAbsorptionBuilder.h
 ";
@@ -5695,7 +5695,7 @@ Indicates if the peak shape encodes angular disorder, in which case all peaks in
 // File: classMultiLayer.xml
 %feature("docstring") MultiLayer "
 
-Our sample model: a stack of layers one below the other.Example of system of 4 layers (3 interfaces):
+Our sample model: a stack of layers one below the other. Example of system of 4 layers (3 interfaces):
 
 ambience layer #0 ------ interface #0 z=0.0 Fe, 20A layer #1 ------ interface #1 z=-20.0 Cr, 40A layer #2 ------ interface #2 z=-60.0 substrate layer #3
 
@@ -7618,124 +7618,124 @@ C++ includes: ZLimits.h
 ";
 
 
-// File: namespace_0D122.xml
+// File: namespace_0d122.xml
 
 
-// File: namespace_0D125.xml
+// File: namespace_0d125.xml
 
 
-// File: namespace_0D149.xml
+// File: namespace_0d149.xml
 
 
-// File: namespace_0D153.xml
+// File: namespace_0d153.xml
 
 
-// File: namespace_0D157.xml
+// File: namespace_0d157.xml
 
 
-// File: namespace_0D16.xml
+// File: namespace_0d16.xml
 
 
-// File: namespace_0D167.xml
+// File: namespace_0d167.xml
 
 
-// File: namespace_0D169.xml
+// File: namespace_0d169.xml
 
 
-// File: namespace_0D171.xml
+// File: namespace_0d171.xml
 
 
-// File: namespace_0D181.xml
+// File: namespace_0d181.xml
 
 
-// File: namespace_0D2.xml
+// File: namespace_0d2.xml
 
 
-// File: namespace_0D201.xml
+// File: namespace_0d201.xml
 
 
-// File: namespace_0D203.xml
+// File: namespace_0d203.xml
 
 
-// File: namespace_0D205.xml
+// File: namespace_0d205.xml
 
 
-// File: namespace_0D210.xml
+// File: namespace_0d210.xml
 
 
-// File: namespace_0D212.xml
+// File: namespace_0d212.xml
 
 
-// File: namespace_0D222.xml
+// File: namespace_0d222.xml
 
 
-// File: namespace_0D236.xml
+// File: namespace_0d236.xml
 
 
-// File: namespace_0D241.xml
+// File: namespace_0d241.xml
 
 
-// File: namespace_0D25.xml
+// File: namespace_0d25.xml
 
 
-// File: namespace_0D259.xml
+// File: namespace_0d259.xml
 
 
-// File: namespace_0D267.xml
+// File: namespace_0d267.xml
 
 
-// File: namespace_0D277.xml
+// File: namespace_0d277.xml
 
 
-// File: namespace_0D279.xml
+// File: namespace_0d279.xml
 
 
-// File: namespace_0D281.xml
+// File: namespace_0d281.xml
 
 
-// File: namespace_0D283.xml
+// File: namespace_0d283.xml
 
 
-// File: namespace_0D285.xml
+// File: namespace_0d285.xml
 
 
-// File: namespace_0D289.xml
+// File: namespace_0d289.xml
 
 
-// File: namespace_0D291.xml
+// File: namespace_0d291.xml
 
 
-// File: namespace_0D295.xml
+// File: namespace_0d295.xml
 
 
-// File: namespace_0D307.xml
+// File: namespace_0d307.xml
 
 
-// File: namespace_0D31.xml
+// File: namespace_0d31.xml
 
 
-// File: namespace_0D313.xml
+// File: namespace_0d313.xml
 
 
-// File: namespace_0D317.xml
+// File: namespace_0d317.xml
 
 
-// File: namespace_0D335.xml
+// File: namespace_0d335.xml
 
 
-// File: namespace_0D354.xml
+// File: namespace_0d354.xml
 
 
-// File: namespace_0D37.xml
+// File: namespace_0d37.xml
 
 
-// File: namespace_0D39.xml
+// File: namespace_0d39.xml
 
 
-// File: namespace_0D4.xml
+// File: namespace_0d4.xml
 
 
-// File: namespace_0D47.xml
+// File: namespace_0d47.xml
 
 
 // File: namespacebake.xml
@@ -7803,7 +7803,7 @@ Function for calculating the reduced potential, used for obtaining the Fresnel c
 %feature("docstring")  MaterialUtils::MagnetizationCorrection "Eigen::Matrix2cd MaterialUtils::MagnetizationCorrection(complex_t unit_factor, double magnetic_factor, BasicVector3D< T > polarization)
 ";
 
-%feature("docstring")  MaterialUtils::checkMaterialTypes "MATERIAL_TYPES MaterialUtils::checkMaterialTypes(const std::vector< const Material *> &materials)
+%feature("docstring")  MaterialUtils::checkMaterialTypes "MATERIAL_TYPES MaterialUtils::checkMaterialTypes(const std::vector< const Material * > &materials)
 
 Checks if all non-default materials in  materials are of the same type and returns this type. If several types of materials are involved, InvalidMaterialType identifier is returned. 
 ";
diff --git a/auto/Wrap/libBornAgainSample.py b/auto/Wrap/libBornAgainSample.py
index a41337f82643c3988ce2325456ff3383e6b8651d..2428c736f440103466448105468182b2ad4a8c3f 100644
--- a/auto/Wrap/libBornAgainSample.py
+++ b/auto/Wrap/libBornAgainSample.py
@@ -8406,7 +8406,7 @@ class MultiLayer(ISample):
     r"""
 
 
-    Our sample model: a stack of layers one below the other.Example of system of 4 layers (3 interfaces):
+    Our sample model: a stack of layers one below the other. Example of system of 4 layers (3 interfaces):
 
     ambience layer #0 ------ interface #0 z=0.0 Fe, 20A layer #1 ------ interface #1 z=-20.0 Cr, 40A layer #2 ------ interface #2 z=-60.0 substrate layer #3
 
diff --git a/devtools/code-tools/normalize-usercode.py b/devtools/code-tools/normalize-usercode.py
index b1d2436780de887e9d543cfdda7b8d492055a8c9..30c55dd96d9884fe1060ec393da533fd1bb4ac39 100755
--- a/devtools/code-tools/normalize-usercode.py
+++ b/devtools/code-tools/normalize-usercode.py
@@ -8,19 +8,30 @@ Export to normal form is done by BornAgain's ExportToPython function.
 import argparse
 import bornagain as ba
 
-def normalize_script(fname, inplace):
-    with open(fname, 'rb') as f:
-        ti = f.read()
+def normalize_text(ti):
     c=compile(ti, fname, 'exec')
     ns = {}
     exec(c,ns)
     globals().update(ns)
     s = get_simulation()
     s.setSample(get_sample())
-    t = ba.generatePyExportTest(s)
+    return ba.generatePyExportTest(s)
+
+def normalize_file(fname, inplace):
+    with open(fname, 'rb') as f:
+        ti = f.read()
+    t = normalize_text(ti)
     if t == ti:
         print(f'Nothing changed in file {fname}')
         return
+    t2 = normalize_text(t)
+    if t2 != t:
+        with open("out1.py", 'w') as f:
+            f.write(t)
+        with open("out2.py", 'w') as f:
+            f.write(t2)
+        exit("Script changes under second normalization, see files out1.py and out2.py")
+
     if inplace:
         with open(fname, 'w') as f:
             f.write(t)
@@ -34,4 +45,4 @@ if __name__ == '__main__':
     parser.add_argument("-i", "--in-place", action="store_true")
     args = parser.parse_args()
 
-    normalize_script(args.simulation_script, args.in_place)
+    normalize_file(args.simulation_script, args.in_place)