diff --git a/continuous_distribution_measures.py b/continuous_distribution_measures.py
index 1afb4859f6ecdf749d5c8cd9333928b880cba23d..866093c5e89a243a942b23f25b3df8f3ba518ad6 100644
--- a/continuous_distribution_measures.py
+++ b/continuous_distribution_measures.py
@@ -31,7 +31,6 @@ def momentGeneratingFunction(function, symbols, symbolsInResult):
 
     """
     assert len(symbols) == len(symbolsInResult)
-
     for t_i, v_i in zip(symbolsInResult, symbols):
         function *= sp.exp(t_i * v_i)
 
diff --git a/cumulants.py b/cumulants.py
index 4e8093788f3fd186e1ead084282469f066411963..1cec741ed8dcaace6bc2f0e7d191b408b9dcd9ba 100644
--- a/cumulants.py
+++ b/cumulants.py
@@ -162,7 +162,8 @@ def cumulantsFromPdfs(stencil, cumulantIndices=None, pdfSymbols=None):
     if cumulantIndices is None:
         cumulantIndices = momentsUpToComponentOrder(2, dim=dim)
     assert len(stencil) == len(cumulantIndices), "Stencil has to have same length as cumulantIndices sequence"
-    pdfSymbols = __getIndexedSymbols(pdfSymbols, "f", range(len(stencil)))
+    if pdfSymbols is None:
+        pdfSymbols = __getIndexedSymbols(pdfSymbols, "f", range(len(stencil)))
     return {idx: discreteCumulant(tuple(pdfSymbols), idx, stencil) for idx in cumulantIndices}
 
 
diff --git a/forcemodels.py b/forcemodels.py
index ff767b4ff5df728e38bc5ac0899704043c75fa35..f12b470255fa9f58d3dedcb4d67f0edf038b85ef 100644
--- a/forcemodels.py
+++ b/forcemodels.py
@@ -64,7 +64,6 @@ class Guo:
 
     def __call__(self, lbmMethod):
         luo = Luo(self._force)
-        u = lbmMethod.firstOrderEquilibriumMomentSymbols
         shearRelaxationRate = lbmMethod.getShearRelaxationRate()
         correctionFactor = (1 - sp.Rational(1, 2) * shearRelaxationRate)
         return [correctionFactor * t for t in luo(lbmMethod)]
diff --git a/maxwellian_equilibrium.py b/maxwellian_equilibrium.py
index 9af585f2a7113997988cf51fba9528c74f12e510..3fc185cfe99eb35aa7308582e2ab482873b216d8 100644
--- a/maxwellian_equilibrium.py
+++ b/maxwellian_equilibrium.py
@@ -171,8 +171,8 @@ def getMomentsOfContinuousMaxwellianEquilibrium(moments, dim, rho=sp.Symbol("rho
 
 
 @diskcache
-def getMomentsOfDiscreteMaxwellianEquilibrium(stencil,
-                                              moments, rho=sp.Symbol("rho"), u=tuple(sp.symbols("u_0 u_1 u_2")),
+def getMomentsOfDiscreteMaxwellianEquilibrium(stencil, moments,
+                                              rho=sp.Symbol("rho"), u=tuple(sp.symbols("u_0 u_1 u_2")),
                                               c_s_sq=sp.Symbol("c_s") ** 2, order=None, compressible=True):
     """
     Compute moments of discrete maxwellian equilibrium
@@ -195,13 +195,30 @@ def getMomentsOfDiscreteMaxwellianEquilibrium(stencil,
 # -------------------------------- Equilibrium moments -----------------------------------------------------------------
 
 
-def getCumulantsOfContinuousMaxwellianEquilibrium(cumulants, rho=sp.Symbol("rho"), u=tuple(sp.symbols("u_0 u_1 u_2")),
-                                                  c_s_sq=sp.Symbol("c_s") ** 2, dim=3):
+def getCumulantsOfContinuousMaxwellianEquilibrium(cumulants, dim, rho=sp.Symbol("rho"), u=tuple(sp.symbols("u_0 u_1 u_2")),
+                                                  c_s_sq=sp.Symbol("c_s") ** 2, order=None):
     from lbmpy.moments import MOMENT_SYMBOLS
     from lbmpy.continuous_distribution_measures import continuousCumulant
+    from pystencils.sympyextensions import removeHigherOrderTerms
 
-    mb = continuousMaxwellianEquilibrium(dim, rho, u, MOMENT_SYMBOLS[:dim], c_s_sq)
-    result = [continuousCumulant(mb, cumulant, MOMENT_SYMBOLS[:dim]) for cumulant in cumulants]
+    # trick to speed up sympy integration (otherwise it takes multiple minutes, or aborts):
+    # use a positive, real symbol to represent c_s_sq -> then replace this symbol afterwards with the real c_s_sq
+    c_s_sq_helper = sp.Symbol("csqHelper", positive=True, real=True)
+    mb = continuousMaxwellianEquilibrium(dim, rho, u, MOMENT_SYMBOLS[:dim], c_s_sq_helper)
+    result = [continuousCumulant(mb, cumulant, MOMENT_SYMBOLS[:dim]).subs(c_s_sq_helper, c_s_sq) for cumulant in cumulants]
+    if order is not None:
+        result = [removeHigherOrderTerms(r, order, u) for r in result]
 
     return result
 
+
+@diskcache
+def getCumulantsOfDiscreteMaxwellianEquilibrium(stencil, cumulants,
+                                                rho=sp.Symbol("rho"), u=tuple(sp.symbols("u_0 u_1 u_2")),
+                                                c_s_sq=sp.Symbol("c_s") ** 2, order=None, compressible=True):
+    from lbmpy.cumulants import discreteCumulant
+    if order is None:
+        order = 4
+    mb = discreteMaxwellianEquilibrium(stencil, rho, u, order, c_s_sq, compressible)
+    return tuple([discreteCumulant(mb, cumulant, stencil).expand() for cumulant in cumulants])
+
diff --git a/methods/conservedquantitycomputation.py b/methods/conservedquantitycomputation.py
index 40b00fca6f926eaf7a783ca1c6831ec01a219a17..daf6bbf6d662611cbfb8697739e4466085705fb1 100644
--- a/methods/conservedquantitycomputation.py
+++ b/methods/conservedquantitycomputation.py
@@ -103,6 +103,14 @@ class DensityVelocityComputation(AbstractConservedQuantityComputation):
         else:
             return None
 
+    @property
+    def zerothOrderMomentSymbol(self):
+        return self._symbolOrder0
+
+    @property
+    def firstOrderMomentSymbol(self):
+        return self._symbolsOrder1
+
     @property
     def defaultValues(self):
         result = {self._symbolOrder0: 1}
diff --git a/methods/cumulantbased.py b/methods/cumulantbased.py
index 86a09e4a6fe4219fac76c9b4e3650c76491df2e2..4b6161df462b226d19a336813dec463d0e43f0dd 100644
--- a/methods/cumulantbased.py
+++ b/methods/cumulantbased.py
@@ -2,8 +2,9 @@ import sympy as sp
 from collections import OrderedDict
 from lbmpy.methods.abstractlbmethod import AbstractLbMethod, LbmCollisionRule, RelaxationInfo
 from lbmpy.methods.conservedquantitycomputation import AbstractConservedQuantityComputation
-from lbmpy.moments import MOMENT_SYMBOLS
-from lbmpy.cumulants import cumulantsFromPdfs
+from lbmpy.moments import MOMENT_SYMBOLS, extractMonomials, momentMatrix, monomialToPolynomialTransformationMatrix
+from lbmpy.cumulants import cumulantAsFunctionOfRawMoments, rawMomentAsFunctionOfCumulants
+from pystencils.sympyextensions import fastSubs, replaceAdditive
 
 
 class CumulantBasedLbMethod(AbstractLbMethod):
@@ -15,6 +16,7 @@ class CumulantBasedLbMethod(AbstractLbMethod):
         self._forceModel = forceModel
         self._cumulantToRelaxationInfoDict = OrderedDict(cumulantToRelaxationInfoDict.items())
         self._conservedQuantityComputation = conservedQuantityComputation
+        self._weights = None
 
     @property
     def cumulantToRelaxationInfoDict(self):
@@ -29,17 +31,27 @@ class CumulantBasedLbMethod(AbstractLbMethod):
             self._cumulantToRelaxationInfoDict[e] = newEntry
 
     @property
-    def moments(self):
+    def cumulants(self):
         return tuple(self._cumulantToRelaxationInfoDict.keys())
 
     @property
-    def momentEquilibriumValues(self):
+    def cumulantEquilibriumValues(self):
         return tuple([e.equilibriumValue for e in self._cumulantToRelaxationInfoDict.values()])
 
     @property
     def relaxationRates(self):
         return tuple([e.relaxationRate for e in self._cumulantToRelaxationInfoDict.values()])
 
+    @property
+    def conservedQuantityComputation(self):
+        return self._conservedQuantityComputation
+
+    @property
+    def weights(self):
+        if self._weights is None:
+            self._weights = self._computeWeights()
+        return self._weights
+
     def _repr_html_(self):
         table = """
         <table style="border:none; width: 100%">
@@ -68,28 +80,102 @@ class CumulantBasedLbMethod(AbstractLbMethod):
 
     def getEquilibrium(self, conservedQuantityEquations=None):
         D = sp.eye(len(self.relaxationRates))
-        return self._getCollisionRuleWithRelaxationMatrix(D, conservedQuantityEquations=conservedQuantityEquations)
-
-    def getCollisionRule(self, conservedQuantityEquations=None):
-        # Step 1: transform input into cumulant space
-
-        cumulantsFromPdfs(self.stencil, )
-        # Step 2: create linear transformation from basic cumulants to requested cumulants
-
-        # Step 3: relaxation
+        return self._getCollisionRuleWithRelaxationMatrix(D, conservedQuantityEquations, False, False, False)
+
+    def getCollisionRule(self, conservedQuantityEquations=None, momentSubexpressions=False,
+                         preCollisionSubexpressions=True, postCollisionSubexpressions=False):
+        return self._getCollisionRuleWithRelaxationMatrix(sp.diag(*self.relaxationRates), conservedQuantityEquations,
+                                                          momentSubexpressions, preCollisionSubexpressions,
+                                                          postCollisionSubexpressions)
+
+    def _computeWeights(self):
+        replacements = self._conservedQuantityComputation.defaultValues
+        eqColl = self.getEquilibrium().copyWithSubstitutionsApplied(replacements).insertSubexpressions()
+        newMainEqs = [sp.Eq(e.lhs,
+                            replaceAdditive(e.rhs, 1, sum(self.preCollisionPdfSymbols), requiredMatchReplacement=1.0))
+                      for e in eqColl.mainEquations]
+        eqColl = eqColl.copy(newMainEqs)
+
+        weights = []
+        for eq in eqColl.mainEquations:
+            value = eq.rhs.expand()
+            assert len(value.atoms(sp.Symbol)) == 0, "Failed to compute weights"
+            weights.append(value)
+        return weights
+
+    def _getCollisionRuleWithRelaxationMatrix(self, relaxationMatrix, conservedQuantityEquations=None,
+                                              momentSubexpressions=False, preCollisionSubexpressions=True,
+                                              postCollisionSubexpressions=False):
+        def tupleToSymbol(exp, prefix):
+            dim = len(exp)
+            formatString = prefix + "_" + "_".join(["%d"]*dim)
+            return sp.Symbol(formatString % exp)
+
+        def substituteConservedQuantities(expressions, cqe):
+            cqe = cqe.insertSubexpressions()
+            substitutionDict = {eq.rhs: eq.lhs for eq in cqe.mainEquations}
+            density = cqe.mainEquations[0].lhs
+            substitutionDict.update({density * eq.rhs: density * eq.lhs for eq in cqe.mainEquations[1:]})
+            return [fastSubs(e, substitutionDict) for e in expressions]
+
+        f = self.preCollisionPdfSymbols
+        if conservedQuantityEquations is None:
+            conservedQuantityEquations = self._conservedQuantityComputation.equilibriumInputEquationsFromPdfs(f)
+
+        subexpressions = conservedQuantityEquations.allEquations
+
+        # 1) Determine monomial indices, and arange them such that the zeroth and first order indices come first
+        indices = list(extractMonomials(self.cumulants, dim=len(self.stencil[0])))
+        zerothMomentExponent = (0,) * self.dim
+        firstMomentExponents = [tuple([1 if i == j else 0 for i in range(self.dim)]) for j in range(self.dim)]
+        lowerOrderIndices = [zerothMomentExponent] + firstMomentExponents
+        numLowerOrderIndices = len(lowerOrderIndices)
+        assert all(e in indices for e in lowerOrderIndices), \
+            "Cumulant system does not contain relaxation rules for zeroth and first order cumulants"
+        higherOrderIndices = [e for e in indices if e not in lowerOrderIndices]
+        indices = lowerOrderIndices + higherOrderIndices  # reorder
+
+        # 2) Transform pdfs to moments
+        momentTransformationMatrix = momentMatrix(indices, self.stencil)
+        moments = momentTransformationMatrix * sp.Matrix(f)
+        moments = substituteConservedQuantities(moments, conservedQuantityEquations)
+        if momentSubexpressions:
+            symbols = [tupleToSymbol(t, "m") for t in higherOrderIndices]
+            subexpressions += [sp.Eq(sym, moment) for sym, moment in zip(symbols, moments[numLowerOrderIndices:])]
+            moments = moments[:numLowerOrderIndices] + symbols
+
+        # 3) Transform moments to monomial cumulants
+        momentsDict = {idx: m for idx, m in zip(indices, moments)}
+        monomialCumulants = [cumulantAsFunctionOfRawMoments(idx, momentsDict) for idx in indices]
+
+        if preCollisionSubexpressions:
+            symbols = [tupleToSymbol(t, "preC") for t in higherOrderIndices]
+            subexpressions += [sp.Eq(sym, c)
+                               for sym, c in zip(symbols, monomialCumulants[numLowerOrderIndices:])]
+            monomialCumulants = monomialCumulants[:numLowerOrderIndices] + symbols
+
+        # 4) Transform monomial to polynomial cumulants which are then relaxed and transformed back
+        monToPoly = monomialToPolynomialTransformationMatrix(indices, self.cumulants)
+        polyValues = monToPoly * sp.Matrix(monomialCumulants)
+        eqValues = sp.Matrix(self.cumulantEquilibriumValues)
+        collidedPolyValues = polyValues + relaxationMatrix * (eqValues - polyValues)  # collision
+        relaxedMonomialCumulants = monToPoly.inv() * collidedPolyValues
+
+        if postCollisionSubexpressions:
+            symbols = [tupleToSymbol(t, "postC") for t in higherOrderIndices]
+            subexpressions += [sp.Eq(sym, c)
+                               for sym, c in zip(symbols, relaxedMonomialCumulants[numLowerOrderIndices:])]
+            relaxedMonomialCumulants = relaxedMonomialCumulants[:numLowerOrderIndices] + symbols
+
+        # 5) Transform post-collision cumulant back to moments and from there to pdfs
+        cumulantDict = {idx: value for idx, value in zip(indices, relaxedMonomialCumulants)}
+        collidedMoments = [rawMomentAsFunctionOfCumulants(idx, cumulantDict) for idx in indices]
+        result = momentTransformationMatrix.inv() * sp.Matrix(collidedMoments)
+        mainEquations = [sp.Eq(sym, val) for sym, val in zip(self.postCollisionPdfSymbols, result)]
+
+        return LbmCollisionRule(self, mainEquations, subexpressions, simplificationHints={})
 
-        # Step 4: transform back into standard cumulants
 
-        # Step 5: transform cumulants to moments
 
-        # Step 6: transform moments to pdfs
 
-        D = sp.diag(*self.relaxationRates)
-        relaxationRateSubExpressions, D = self._generateRelaxationMatrix(D)
-        eqColl = self._getCollisionRuleWithRelaxationMatrix(D, relaxationRateSubExpressions, conservedQuantityEquations)
-        if self._forceModel is not None:
-            forceModelTerms = self._forceModel(self)
-            newEqs = [sp.Eq(eq.lhs, eq.rhs + fmt) for eq, fmt in zip(eqColl.mainEquations, forceModelTerms)]
-            eqColl = eqColl.copy(newEqs)
-        return eqColl
 
diff --git a/methods/momentbased.py b/methods/momentbased.py
index abd3903f83af20330dc623c3588a3160698e9f52..35626f81bb93dacfda9b74078a30088fc478dc8a 100644
--- a/methods/momentbased.py
+++ b/methods/momentbased.py
@@ -4,7 +4,8 @@ from collections import OrderedDict, defaultdict
 
 from lbmpy.stencils import stencilsHaveSameEntries, getStencil
 from lbmpy.maxwellian_equilibrium import getMomentsOfDiscreteMaxwellianEquilibrium, \
-    getMomentsOfContinuousMaxwellianEquilibrium
+    getMomentsOfContinuousMaxwellianEquilibrium, getCumulantsOfDiscreteMaxwellianEquilibrium, \
+    getCumulantsOfContinuousMaxwellianEquilibrium
 from lbmpy.methods.abstractlbmethod import AbstractLbMethod, LbmCollisionRule, RelaxationInfo
 from lbmpy.methods.conservedquantitycomputation import AbstractConservedQuantityComputation, DensityVelocityComputation
 from lbmpy.moments import MOMENT_SYMBOLS, momentMatrix, isShearMoment, \
@@ -74,11 +75,11 @@ class MomentBasedLbMethod(AbstractLbMethod):
 
     @property
     def zerothOrderEquilibriumMomentSymbol(self, ):
-        return self._conservedQuantityComputation.definedSymbols(order=0)[1]
+        return self._conservedQuantityComputation.zerothOrderMomentSymbol
 
     @property
     def firstOrderEquilibriumMomentSymbols(self, ):
-        return self._conservedQuantityComputation.definedSymbols(order=1)[1]
+        return self._conservedQuantityComputation.firstOrderMomentsSymbol
 
     @property
     def weights(self):
@@ -273,9 +274,12 @@ def compressibleToIncompressibleMomentValue(term, rho, u):
     return res
 
 
+from lbmpy.methods.cumulantbased import CumulantBasedLbMethod
+
+
 def createWithDiscreteMaxwellianEqMoments(stencil, momentToRelaxationRateDict, compressible=False, forceModel=None,
-                                          equilibriumAccuracyOrder=2):
-    """
+                                          equilibriumAccuracyOrder=2, cumulant=False):
+    r"""
     Creates a moment-based LBM by taking a list of moments with corresponding relaxation rate. These moments are
     relaxed against the moments of the discrete Maxwellian distribution.
 
@@ -283,9 +287,13 @@ def createWithDiscreteMaxwellianEqMoments(stencil, momentToRelaxationRateDict, c
     :param momentToRelaxationRateDict: dict that has as many entries as the stencil. Each moment, which can be
                                        represented by an exponent tuple or in polynomial form
                                        (see `lbmpy.moments`), is mapped to a relaxation rate.
-    :param compressible: using the compressible or incompressible discrete Maxwellian
+    :param compressible: incompressible LBM methods split the density into :math:`\rho = \rho_0 + \Delta \rho`
+         where :math:`\rho_0` is chosen as one, and the first moment of the pdfs is :math:`\Delta \rho` .
+         This approximates the incompressible Navier-Stokes equations better than the standard
+         compressible model.
     :param forceModel: force model instance, or None if no external forces
     :param equilibriumAccuracyOrder: approximation order of macroscopic velocity :math:`\mathbf{u}` in the equilibrium
+    :param cumulant: if True relax cumulants instead of moments
     :return: :class:`lbmpy.methods.MomentBasedLbmMethod` instance
     """
     momToRrDict = OrderedDict(momentToRelaxationRateDict)
@@ -293,16 +301,27 @@ def createWithDiscreteMaxwellianEqMoments(stencil, momentToRelaxationRateDict, c
         "The number of moments has to be the same as the number of stencil entries"
 
     densityVelocityComputation = DensityVelocityComputation(stencil, compressible, forceModel)
-    eqMoments = getMomentsOfDiscreteMaxwellianEquilibrium(stencil, list(momToRrDict.keys()), c_s_sq=sp.Rational(1, 3),
-                                                          compressible=compressible, order=equilibriumAccuracyOrder)
+
+    if cumulant:
+        eqValues = getCumulantsOfDiscreteMaxwellianEquilibrium(stencil, list(momToRrDict.keys()),
+                                                               c_s_sq=sp.Rational(1, 3), compressible=compressible,
+                                                               order=equilibriumAccuracyOrder)
+    else:
+        eqValues = getMomentsOfDiscreteMaxwellianEquilibrium(stencil, list(momToRrDict.keys()),
+                                                             c_s_sq=sp.Rational(1, 3), compressible=compressible,
+                                                             order=equilibriumAccuracyOrder)
+
     rrDict = OrderedDict([(mom, RelaxationInfo(eqMom, rr))
-                          for mom, rr, eqMom in zip(momToRrDict.keys(), momToRrDict.values(), eqMoments)])
-    return MomentBasedLbMethod(stencil, rrDict, densityVelocityComputation, forceModel)
+                          for mom, rr, eqMom in zip(momToRrDict.keys(), momToRrDict.values(), eqValues)])
+    if cumulant:
+        return CumulantBasedLbMethod(stencil, rrDict, densityVelocityComputation, forceModel)
+    else:
+        return MomentBasedLbMethod(stencil, rrDict, densityVelocityComputation, forceModel)
 
 
 def createWithContinuousMaxwellianEqMoments(stencil, momentToRelaxationRateDict, compressible=False, forceModel=None,
-                                            equilibriumAccuracyOrder=None):
-    """
+                                            equilibriumAccuracyOrder=2, cumulant=False):
+    r"""
     Creates a moment-based LBM by taking a list of moments with corresponding relaxation rate. These moments are
     relaxed against the moments of the continuous Maxwellian distribution.
     For parameter description see :func:`lbmpy.methods.createWithDiscreteMaxwellianEqMoments`.
@@ -313,44 +332,50 @@ def createWithContinuousMaxwellianEqMoments(stencil, momentToRelaxationRateDict,
         stencil), "The number of moments has to be the same as the number of stencil entries"
     dim = len(stencil[0])
     densityVelocityComputation = DensityVelocityComputation(stencil, True, forceModel)
-    eqMoments = getMomentsOfContinuousMaxwellianEquilibrium(list(momToRrDict.keys()), dim, c_s_sq=sp.Rational(1, 3),
-                                                            order=equilibriumAccuracyOrder)
+
+    if cumulant:
+        eqValues = getCumulantsOfContinuousMaxwellianEquilibrium(list(momToRrDict.keys()), dim,
+                                                                 c_s_sq=sp.Rational(1, 3),
+                                                                 order=equilibriumAccuracyOrder)
+    else:
+        eqValues = getMomentsOfContinuousMaxwellianEquilibrium(list(momToRrDict.keys()), dim, c_s_sq=sp.Rational(1, 3),
+                                                               order=equilibriumAccuracyOrder)
 
     if not compressible:
         rho = densityVelocityComputation.definedSymbols(order=0)[1]
         u = densityVelocityComputation.definedSymbols(order=1)[1]
-        eqMoments = [compressibleToIncompressibleMomentValue(em, rho, u) for em in eqMoments]
+        eqValues = [compressibleToIncompressibleMomentValue(em, rho, u) for em in eqValues]
 
     rrDict = OrderedDict([(mom, RelaxationInfo(eqMom, rr))
-                          for mom, rr, eqMom in zip(momToRrDict.keys(), momToRrDict.values(), eqMoments)])
-    return MomentBasedLbMethod(stencil, rrDict, densityVelocityComputation, forceModel)
+                          for mom, rr, eqMom in zip(momToRrDict.keys(), momToRrDict.values(), eqValues)])
+    if cumulant:
+        return CumulantBasedLbMethod(stencil, rrDict, densityVelocityComputation, forceModel)
+    else:
+        return MomentBasedLbMethod(stencil, rrDict, densityVelocityComputation, forceModel)
 
 
 # ------------------------------------ SRT / TRT/ MRT Creators ---------------------------------------------------------
 
 
-def createSRT(stencil, relaxationRate, compressible=False, forceModel=None, equilibriumAccuracyOrder=2):
+def createSRT(stencil, relaxationRate, useContinuousMaxwellianEquilibrium=False, **kwargs):
     r"""
     Creates a single relaxation time (SRT) lattice Boltzmann model also known as BGK model.
 
     :param stencil: nested tuple defining the discrete velocity space. See :func:`lbmpy.stencils.getStencil`
     :param relaxationRate: relaxation rate (inverse of the relaxation time)
                            usually called :math:`\omega` in LBM literature
-    :param compressible: incompressible LBM methods split the density into :math:`\rho = \rho_0 + \Delta \rho`
-             where :math:`\rho_0` is chosen as one, and the first moment of the pdfs is :math:`\Delta \rho` .
-             This approximates the incompressible Navier-Stokes equations better than the standard
-             compressible model.
-    :param forceModel: force model instance, or None if no external forces
-    :param equilibriumAccuracyOrder: approximation order of macroscopic velocity :math:`\mathbf{u}` in the equilibrium
     :return: :class:`lbmpy.methods.MomentBasedLbmMethod` instance
     """
     moments = getDefaultMomentSetForStencil(stencil)
     rrDict = OrderedDict([(m, relaxationRate) for m in moments])
-    return createWithDiscreteMaxwellianEqMoments(stencil, rrDict, compressible, forceModel, equilibriumAccuracyOrder)
+    if useContinuousMaxwellianEquilibrium:
+        return createWithContinuousMaxwellianEqMoments(stencil, rrDict,  **kwargs)
+    else:
+        return createWithDiscreteMaxwellianEqMoments(stencil, rrDict, **kwargs)
 
 
-def createTRT(stencil, relaxationRateEvenMoments, relaxationRateOddMoments, compressible=False,
-              forceModel=None, equilibriumAccuracyOrder=2):
+def createTRT(stencil, relaxationRateEvenMoments, relaxationRateOddMoments,
+              useContinuousMaxwellianEquilibrium=False, **kwargs):
     """
     Creates a two relaxation time (TRT) lattice Boltzmann model, where even and odd moments are relaxed differently.
     In the SRT model the exact wall position of no-slip boundaries depends on the viscosity, the TRT method does not
@@ -362,21 +387,23 @@ def createTRT(stencil, relaxationRateEvenMoments, relaxationRateOddMoments, comp
     """
     moments = getDefaultMomentSetForStencil(stencil)
     rrDict = OrderedDict([(m, relaxationRateEvenMoments if isEven(m) else relaxationRateOddMoments) for m in moments])
-    return createWithDiscreteMaxwellianEqMoments(stencil, rrDict, compressible, forceModel, equilibriumAccuracyOrder)
+    if useContinuousMaxwellianEquilibrium:
+        return createWithContinuousMaxwellianEqMoments(stencil, rrDict,  **kwargs)
+    else:
+        return createWithDiscreteMaxwellianEqMoments(stencil, rrDict, **kwargs)
 
 
-def createTRTWithMagicNumber(stencil, relaxationRate, magicNumber=sp.Rational(3, 16), *args, **kwargs):
+def createTRTWithMagicNumber(stencil, relaxationRate, magicNumber=sp.Rational(3, 16), **kwargs):
     """
     Creates a two relaxation time (TRT) lattice Boltzmann method, where the relaxation time for odd moments is
     determines from the even moment relaxation time and a "magic number".
     For possible parameters see :func:`lbmpy.methods.createTRT`
     """
     rrOdd = relaxationRateFromMagicNumber(relaxationRate, magicNumber)
-    return createTRT(stencil, relaxationRateEvenMoments=relaxationRate, relaxationRateOddMoments=rrOdd, *args, **kwargs)
+    return createTRT(stencil, relaxationRateEvenMoments=relaxationRate, relaxationRateOddMoments=rrOdd, **kwargs)
 
 
-def createOrthogonalMRT(stencil, relaxationRateGetter=None, compressible=False,
-                        forceModel=None, equilibriumAccuracyOrder=2):
+def createOrthogonalMRT(stencil, relaxationRateGetter=None, useContinuousMaxwellianEquilibrium=False, **kwargs):
     r"""
     Returns a orthogonal multi-relaxation time model for the stencils D2Q9, D3Q15, D3Q19 and D3Q27.
     These MRT methods are just one specific version - there are many MRT methods possible for all these stencils
@@ -390,10 +417,6 @@ def createOrthogonalMRT(stencil, relaxationRateGetter=None, compressible=False,
                                     - 0 for moments of order 0 and 1 (conserved)
                                     - :math:`\omega`: from moments of order 2 (rate that determines viscosity)
                                     - numbered :math:`\omega_i` for the rest
-
-    :param compressible: see :func:`lbmpy.methods.createWithDiscreteMaxwellianEqMoments`
-    :param forceModel:  see :func:`lbmpy.methods.createWithDiscreteMaxwellianEqMoments`
-    :param equilibriumAccuracyOrder:  see :func:`lbmpy.methods.createWithDiscreteMaxwellianEqMoments`
     """
     if relaxationRateGetter is None:
         relaxationRateGetter = defaultRelaxationRateNames()
@@ -465,8 +488,10 @@ def createOrthogonalMRT(stencil, relaxationRateGetter=None, compressible=False,
         for m in momentList:
             momentToRelaxationRateDict[m] = rr
 
-    return createWithDiscreteMaxwellianEqMoments(stencil, momentToRelaxationRateDict, compressible, forceModel,
-                                                 equilibriumAccuracyOrder)
+    if useContinuousMaxwellianEquilibrium:
+        return createWithContinuousMaxwellianEqMoments(stencil, momentToRelaxationRateDict, **kwargs)
+    else:
+        return createWithDiscreteMaxwellianEqMoments(stencil, momentToRelaxationRateDict, **kwargs)
 
 
 # ----------------------------------------- Comparison view for notebooks ----------------------------------------------
diff --git a/moments.py b/moments.py
index 600aa5c2db95be3b04d4cfdc9a2634e6e2663fd7..e7a0eff29075bf63933b7fd9234e285ee5fbb188 100644
--- a/moments.py
+++ b/moments.py
@@ -514,3 +514,47 @@ def momentEqualityTableByStencil(nameToStencilDict, moments, truncateOrder=None)
         ipy_table.set_cell_style(cellIdx[0], cellIdx[1], color=color)
 
     return tableDisplay
+
+
+def extractMonomials(sequenceOfPolynomials, dim=3):
+    """
+    Returns a set of exponent tuples of all monomials contained in the given set of polynomials
+    :param sequenceOfPolynomials: sequence of polynomials in the MOMENT_SYMBOLS
+    :param dim: length of returned exponent tuples
+
+    >>> x, y, z = MOMENT_SYMBOLS
+    >>> extractMonomials([x**2 + y**2 + y, y + y**2])
+    {(0, 2, 0), (0, 1, 0), (2, 0, 0)}
+    >>> extractMonomials([x**2 + y**2 + y, y + y**2], dim=2)
+    {(0, 1), (2, 0), (0, 2)}
+    """
+    monomials = set()
+    for polynomial in sequenceOfPolynomials:
+        for factor, exponentTuple in polynomialToExponentRepresentation(polynomial):
+            monomials.add(exponentTuple[:dim])
+    return monomials
+
+
+def monomialToPolynomialTransformationMatrix(monomials, polynomials):
+    """
+    Returns a transformation matrix from a monomial to a polynomial representation
+    :param monomials: sequence of exponent tuples
+    :param polynomials: sequence of polynomials in the MOMENT_SYMBOLS
+
+    >>> x, y, z = MOMENT_SYMBOLS
+    >>> polys = [7 * x**2 + 3 * x + 2 * y **2, \
+                 9 * x**2 - 5 * x]
+    >>> mons = list(extractMonomials(polys, dim=2))
+    >>> monomialToPolynomialTransformationMatrix(mons, polys)
+    Matrix([
+    [7,  3, 2],
+    [9, -5, 0]])
+    """
+    dim = len(monomials[0])
+
+    result = sp.zeros(len(polynomials), len(monomials))
+    for polynomialIdx, polynomial in enumerate(polynomials):
+        for factor, exponentTuple in polynomialToExponentRepresentation(polynomial):
+            exponentTuple = exponentTuple[:dim]
+            result[polynomialIdx, monomials.index(exponentTuple)] = factor
+    return result