diff --git a/Core/Parametrization/ParameterPool.cpp b/Core/Parametrization/ParameterPool.cpp
index b56c0c065e09b3b3ded48bc33c06220cae0262a2..3fbbdd7a2863e01fa8dec0bcc92108abbdb96c9d 100644
--- a/Core/Parametrization/ParameterPool.cpp
+++ b/Core/Parametrization/ParameterPool.cpp
@@ -154,7 +154,7 @@ void ParameterPool::setParameterValue(const std::string& name, double value)
     }
 }
 
-//! Sets parameter value.
+//! Sets value of the nonzero parameters that match _pattern_ ('*' allowed), or throws.
 
 int ParameterPool::setMatchedParametersValue(const std::string& pattern, double value)
 {
@@ -170,6 +170,15 @@ int ParameterPool::setMatchedParametersValue(const std::string& pattern, double
     return npars;
 }
 
+//! Sets value of the one parameter that matches _pattern_ ('*' allowed), or throws.
+
+void ParameterPool::setUniqueMatchValue(const std::string& pattern, double value)
+{
+    if (setMatchedParametersValue(pattern, value) != 1)
+        throw  Exceptions::RuntimeErrorException(
+            "ParameterPool::setUniqueMatchValue: pattern '"+pattern+"' is not unique");
+}
+
 std::vector<std::string> ParameterPool::getParameterNames() const
 {
     std::vector<std::string> result;
diff --git a/Core/Parametrization/ParameterPool.h b/Core/Parametrization/ParameterPool.h
index 5a20d5930b3a681a758142e72998e1432eaff4f0..34074790065f5055da644d9f1775d43de89788ae 100644
--- a/Core/Parametrization/ParameterPool.h
+++ b/Core/Parametrization/ParameterPool.h
@@ -69,6 +69,7 @@ public:
     void setParameterValue(const std::string& name, double value);
 
     int setMatchedParametersValue(const std::string& wildcards, double value);
+    void setUniqueMatchValue(const std::string& pattern, double value);
 
     std::vector<std::string> getParameterNames() const;
 
diff --git a/Core/Particle/ParticleDistribution.cpp b/Core/Particle/ParticleDistribution.cpp
index 096365499c32e64649dc21fbda5a8dd1c486837d..f0d78c269f2d87625491f843605e1bbcdd87c7d9 100644
--- a/Core/Particle/ParticleDistribution.cpp
+++ b/Core/Particle/ParticleDistribution.cpp
@@ -45,11 +45,6 @@ ParticleDistribution* ParticleDistribution::cloneInvertB() const
                                               "cloneInvertB: should never be called");
 }
 
-void ParticleDistribution::accept(ISampleVisitor* visitor) const
-{
-    visitor->visit(this);
-}
-
 std::string ParticleDistribution::to_str(int indent) const
 {
     std::stringstream ss;
@@ -68,53 +63,31 @@ const IMaterial* ParticleDistribution::getAmbientMaterial() const
     return mP_particle->getAmbientMaterial();
 }
 
-//! Initializes list of new particles generated according to a distribution.
+//! Returns particle clones with parameter values drawn from distribution.
+
 std::vector<const IParticle*> ParticleDistribution::generateParticles() const
 {
-    std::unique_ptr<ParameterPool> P_pool(createDistributedParameterPool());
+    std::unique_ptr<ParameterPool> P_pool {mP_particle->createParameterTree()};
     std::string main_par_name = m_par_distribution.getMainParameterName();
-    RealParameter* main_par = P_pool->getUniqueMatch(main_par_name);
-    double main_par_value = main_par->getValue();
-    std::vector<std::string> linked_par_names = m_par_distribution.getLinkedParameterNames();
-    std::map<std::string, double> linked_par_ratio_map;
-    for (const std::string& name: linked_par_names) {
-        RealParameter* linked_par = P_pool->getUniqueMatch(name);
-        double linked_par_value = linked_par->getValue();
-        double linked_ratio = main_par_value == 0 ? 1.0 : linked_par_value / main_par_value;
-        linked_par_ratio_map[name] = linked_ratio;
-    }
+    double main_par_value = P_pool->getUniqueMatch(main_par_name)->getValue();
+
+    // Preset link ratios:
+    std::map<std::string, double> linked_ratios;
+    for (const std::string& name: m_par_distribution.getLinkedParameterNames())
+        linked_ratios[name] = main_par_value == 0 ? 1.0 :
+            P_pool->getUniqueMatch(name)->getValue() / main_par_value;
+
+    // Draw distribution samples; for each sample, create one particle clone:
     std::vector<ParameterSample> main_par_samples = m_par_distribution.generateSamples();
     std::vector<const IParticle*> result;
     for (const ParameterSample& main_sample: main_par_samples ) {
-        double particle_abundance = getAbundance() * main_sample.weight;
         IParticle* p_particle_clone = mP_particle->clone();
-        std::unique_ptr<ParameterPool> P_new_pool(p_particle_clone->createParameterTree());
-        int changed = P_new_pool->setMatchedParametersValue(main_par_name, main_sample.value);
-        if (changed != 1)
-            throw Exceptions::RuntimeErrorException(
-                "ParticleDistribution::generateParticles: "
-                "main parameter name matches nothing or more than one parameter");
-        for (std::map<std::string, double>::const_iterator it = linked_par_ratio_map.begin();
-             it != linked_par_ratio_map.end(); ++it) {
-            double new_linked_value = main_sample.value * it->second;
-            changed = P_new_pool->setMatchedParametersValue(it->first, new_linked_value);
-            if (changed != 1)
-                throw Exceptions::RuntimeErrorException(
-                    "ParticleDistribution::generateParticles: "
-                    "linked parameter name matches nothing or more than one parameter");
-        }
-        p_particle_clone->setAbundance(particle_abundance);
+        std::unique_ptr<ParameterPool> P_new_pool {p_particle_clone->createParameterTree()};
+        P_new_pool->setUniqueMatchValue(main_par_name, main_sample.value);
+        for (auto it = linked_ratios.begin(); it != linked_ratios.end(); ++it)
+            P_new_pool->setUniqueMatchValue(it->first, main_sample.value * it->second);
+        p_particle_clone->setAbundance(getAbundance() * main_sample.weight);
         result.push_back(p_particle_clone);
     }
     return result;
 }
-
-ParameterPool* ParticleDistribution::createDistributedParameterPool() const
-{
-    return mP_particle->createParameterTree();
-}
-
-const IParticle* ParticleDistribution::getParticle() const
-{
-    return mP_particle.get();
-}
diff --git a/Core/Particle/ParticleDistribution.h b/Core/Particle/ParticleDistribution.h
index 42a9c1740a0eee710aacfbf4f3295934ef476356..3316bd5e4347cea212a5b70426ef9ff430a76e80 100644
--- a/Core/Particle/ParticleDistribution.h
+++ b/Core/Particle/ParticleDistribution.h
@@ -32,7 +32,7 @@ public:
     virtual ParticleDistribution* clone() const;
     virtual ParticleDistribution* cloneInvertB() const;
 
-    virtual void accept(ISampleVisitor* visitor) const;
+    void accept(ISampleVisitor* visitor) const override final { visitor->visit(this); }
 
     //! Returns textual representation of *this and its descendants.
     virtual std::string to_str(int indent=0) const;
@@ -49,11 +49,8 @@ public:
     //! Returns the distributed parameter data
     ParameterDistribution getParameterDistribution() const { return m_par_distribution; }
 
-    //! Returns the parameter pool that can be used for parameter distributions
-    ParameterPool* createDistributedParameterPool() const;
-
     //! Returns particle.
-    const IParticle* getParticle() const;
+    const IParticle* getParticle() const { return mP_particle.get(); }
 
 private:
     std::unique_ptr<IParticle> mP_particle;
diff --git a/auto/Wrap/libBornAgainCore.py b/auto/Wrap/libBornAgainCore.py
index 7d42c5be601c70b1ba457c8ab1f416cf46dbea66..2d4d797c310f61442802ce3fbc9119382fe59504 100644
--- a/auto/Wrap/libBornAgainCore.py
+++ b/auto/Wrap/libBornAgainCore.py
@@ -22483,6 +22483,11 @@ class ParameterPool(_object):
         return _libBornAgainCore.ParameterPool_setMatchedParametersValue(self, wildcards, value)
 
 
+    def setUniqueMatchValue(self, pattern, value):
+        """setUniqueMatchValue(ParameterPool self, std::string const & pattern, double value)"""
+        return _libBornAgainCore.ParameterPool_setUniqueMatchValue(self, pattern, value)
+
+
     def getParameterNames(self):
         """
         getParameterNames(ParameterPool self) -> vector_string_t
@@ -23103,18 +23108,6 @@ class ParticleDistribution(IAbstractParticle):
         return _libBornAgainCore.ParticleDistribution_getParameterDistribution(self)
 
 
-    def createDistributedParameterPool(self):
-        """
-        createDistributedParameterPool(ParticleDistribution self) -> ParameterPool
-
-        ParameterPool * ParticleDistribution::createDistributedParameterPool() const
-
-        Returns the parameter pool that can be used for parameter distributions. 
-
-        """
-        return _libBornAgainCore.ParticleDistribution_createDistributedParameterPool(self)
-
-
     def getParticle(self):
         """
         getParticle(ParticleDistribution self) -> IParticle
diff --git a/auto/Wrap/libBornAgainCore_wrap.cpp b/auto/Wrap/libBornAgainCore_wrap.cpp
index 0c9cbd8d25f7e0f9f38ed2ae73c1a77f83962056..b07ae3b2078836926fb1e3a644fa229a392431a8 100644
--- a/auto/Wrap/libBornAgainCore_wrap.cpp
+++ b/auto/Wrap/libBornAgainCore_wrap.cpp
@@ -92792,6 +92792,52 @@ fail:
 }
 
 
+SWIGINTERN PyObject *_wrap_ParameterPool_setUniqueMatchValue(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  ParameterPool *arg1 = (ParameterPool *) 0 ;
+  std::string *arg2 = 0 ;
+  double arg3 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  int res2 = SWIG_OLDOBJ ;
+  double val3 ;
+  int ecode3 = 0 ;
+  PyObject * obj0 = 0 ;
+  PyObject * obj1 = 0 ;
+  PyObject * obj2 = 0 ;
+  
+  if (!PyArg_ParseTuple(args,(char *)"OOO:ParameterPool_setUniqueMatchValue",&obj0,&obj1,&obj2)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ParameterPool, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ParameterPool_setUniqueMatchValue" "', argument " "1"" of type '" "ParameterPool *""'"); 
+  }
+  arg1 = reinterpret_cast< ParameterPool * >(argp1);
+  {
+    std::string *ptr = (std::string *)0;
+    res2 = SWIG_AsPtr_std_string(obj1, &ptr);
+    if (!SWIG_IsOK(res2)) {
+      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "ParameterPool_setUniqueMatchValue" "', argument " "2"" of type '" "std::string const &""'"); 
+    }
+    if (!ptr) {
+      SWIG_exception_fail(SWIG_ValueError, "invalid null reference " "in method '" "ParameterPool_setUniqueMatchValue" "', argument " "2"" of type '" "std::string const &""'"); 
+    }
+    arg2 = ptr;
+  }
+  ecode3 = SWIG_AsVal_double(obj2, &val3);
+  if (!SWIG_IsOK(ecode3)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "ParameterPool_setUniqueMatchValue" "', argument " "3"" of type '" "double""'");
+  } 
+  arg3 = static_cast< double >(val3);
+  (arg1)->setUniqueMatchValue((std::string const &)*arg2,arg3);
+  resultobj = SWIG_Py_Void();
+  if (SWIG_IsNewObj(res2)) delete arg2;
+  return resultobj;
+fail:
+  if (SWIG_IsNewObj(res2)) delete arg2;
+  return NULL;
+}
+
+
 SWIGINTERN PyObject *_wrap_ParameterPool_getParameterNames(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   ParameterPool *arg1 = (ParameterPool *) 0 ;
@@ -94814,28 +94860,6 @@ fail:
 }
 
 
-SWIGINTERN PyObject *_wrap_ParticleDistribution_createDistributedParameterPool(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *resultobj = 0;
-  ParticleDistribution *arg1 = (ParticleDistribution *) 0 ;
-  void *argp1 = 0 ;
-  int res1 = 0 ;
-  PyObject * obj0 = 0 ;
-  ParameterPool *result = 0 ;
-  
-  if (!PyArg_ParseTuple(args,(char *)"O:ParticleDistribution_createDistributedParameterPool",&obj0)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ParticleDistribution, 0 |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ParticleDistribution_createDistributedParameterPool" "', argument " "1"" of type '" "ParticleDistribution const *""'"); 
-  }
-  arg1 = reinterpret_cast< ParticleDistribution * >(argp1);
-  result = (ParameterPool *)((ParticleDistribution const *)arg1)->createDistributedParameterPool();
-  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_ParameterPool, 0 |  0 );
-  return resultobj;
-fail:
-  return NULL;
-}
-
-
 SWIGINTERN PyObject *_wrap_ParticleDistribution_getParticle(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   ParticleDistribution *arg1 = (ParticleDistribution *) 0 ;
@@ -111947,6 +111971,7 @@ static PyMethodDef SwigMethods[] = {
 		"Sets parameter value. \n"
 		"\n"
 		""},
+	 { (char *)"ParameterPool_setUniqueMatchValue", _wrap_ParameterPool_setUniqueMatchValue, METH_VARARGS, (char *)"ParameterPool_setUniqueMatchValue(ParameterPool self, std::string const & pattern, double value)"},
 	 { (char *)"ParameterPool_getParameterNames", _wrap_ParameterPool_getParameterNames, METH_VARARGS, (char *)"\n"
 		"ParameterPool_getParameterNames(ParameterPool self) -> vector_string_t\n"
 		"\n"
@@ -112302,14 +112327,6 @@ static PyMethodDef SwigMethods[] = {
 		"Returns the distributed parameter data. \n"
 		"\n"
 		""},
-	 { (char *)"ParticleDistribution_createDistributedParameterPool", _wrap_ParticleDistribution_createDistributedParameterPool, METH_VARARGS, (char *)"\n"
-		"ParticleDistribution_createDistributedParameterPool(ParticleDistribution self) -> ParameterPool\n"
-		"\n"
-		"ParameterPool * ParticleDistribution::createDistributedParameterPool() const\n"
-		"\n"
-		"Returns the parameter pool that can be used for parameter distributions. \n"
-		"\n"
-		""},
 	 { (char *)"ParticleDistribution_getParticle", _wrap_ParticleDistribution_getParticle, METH_VARARGS, (char *)"\n"
 		"ParticleDistribution_getParticle(ParticleDistribution self) -> IParticle\n"
 		"\n"