Skip to content
Snippets Groups Projects
Commit a1bb764f authored by Martin Bauer's avatar Martin Bauer
Browse files

started with generalized steady state Chapman Enskog expansion

parent e5dd784b
No related branches found
No related tags found
No related merge requests found
...@@ -25,12 +25,12 @@ def getExpandedName(originalObject, number): ...@@ -25,12 +25,12 @@ def getExpandedName(originalObject, number):
return originalObject.func(newName) return originalObject.func(newName)
def expandedSymbol(name, subscript=None, superscript=None): def expandedSymbol(name, subscript=None, superscript=None, **kwargs):
if subscript is not None: if subscript is not None:
name += "_{%s}" % (subscript,) name += "_{%s}" % (subscript,)
if superscript is not None: if superscript is not None:
name += "^{(%s)}" % (superscript,) name += "^{(%s)}" % (superscript,)
return sp.Symbol(name) return sp.Symbol(name, **kwargs)
# -------------------------------- Summation Convention ------------------------------------------------------------- # -------------------------------- Summation Convention -------------------------------------------------------------
...@@ -383,7 +383,7 @@ def getTaylorExpandedLbEquation(pdfSymbolName="f", pdfsAfterCollisionOperator="\ ...@@ -383,7 +383,7 @@ def getTaylorExpandedLbEquation(pdfSymbolName="f", pdfsAfterCollisionOperator="\
def useChapmanEnskogAnsatz(equation, timeDerivativeOrders=(1, 3), spatialDerivativeOrders=(1, 2), def useChapmanEnskogAnsatz(equation, timeDerivativeOrders=(1, 3), spatialDerivativeOrders=(1, 2),
pdfs=(['f', 0, 3], ['\Omega f', 1, 3])): pdfs=(['f', 0, 3], ['\Omega f', 1, 3]), **kwargs):
t, eps = sp.symbols("t epsilon") t, eps = sp.symbols("t epsilon")
...@@ -406,9 +406,9 @@ def useChapmanEnskogAnsatz(equation, timeDerivativeOrders=(1, 3), spatialDerivat ...@@ -406,9 +406,9 @@ def useChapmanEnskogAnsatz(equation, timeDerivativeOrders=(1, 3), spatialDerivat
for pdfName, startOrder, stopOrder in pdfs: for pdfName, startOrder, stopOrder in pdfs:
if isinstance(pdfName, sp.Symbol): if isinstance(pdfName, sp.Symbol):
pdfName = pdfName.name pdfName = pdfName.name
expandedPdfSymbols += [expandedSymbol(pdfName, superscript=i) for i in range(startOrder, stopOrder)] expandedPdfSymbols += [expandedSymbol(pdfName, superscript=i, **kwargs) for i in range(startOrder, stopOrder)]
subsDict[sp.Symbol(pdfName)] = sum(eps ** i * expandedSymbol(pdfName, superscript=i) subsDict[sp.Symbol(pdfName, **kwargs)] = sum(eps ** i * expandedSymbol(pdfName, superscript=i, **kwargs)
for i in range(startOrder, stopOrder)) for i in range(startOrder, stopOrder))
maxExpansionOrder = max(maxExpansionOrder, stopOrder) maxExpansionOrder = max(maxExpansionOrder, stopOrder)
equation = equation.subs(subsDict) equation = equation.subs(subsDict)
equation = expandUsingLinearity(equation, functions=expandedPdfSymbols).expand().collect(eps) equation = expandUsingLinearity(equation, functions=expandedPdfSymbols).expand().collect(eps)
......
...@@ -78,7 +78,6 @@ class Diff(sp.Expr): ...@@ -78,7 +78,6 @@ class Diff(sp.Expr):
- all simplifications have to be done manually - all simplifications have to be done manually
- each Diff has a Chapman Enskog expansion order index: 'ceIdx' - each Diff has a Chapman Enskog expansion order index: 'ceIdx'
""" """
is_commutative = True
is_number = False is_number = False
is_Rational = False is_Rational = False
...@@ -87,6 +86,14 @@ class Diff(sp.Expr): ...@@ -87,6 +86,14 @@ class Diff(sp.Expr):
return sp.Rational(0, 1) return sp.Rational(0, 1)
return sp.Expr.__new__(cls, argument.expand(), sp.sympify(label), sp.sympify(ceIdx), **kwargs) return sp.Expr.__new__(cls, argument.expand(), sp.sympify(label), sp.sympify(ceIdx), **kwargs)
@property
def is_commutative(self):
anyNonCommutative = any(not s.is_commutative for s in self.atoms(sp.Symbol))
if anyNonCommutative:
return False
else:
return True
def getArgRecursive(self): def getArgRecursive(self):
"""Returns the argument the derivative acts on, for nested derivatives the inner argument is returned""" """Returns the argument the derivative acts on, for nested derivatives the inner argument is returned"""
if not isinstance(self.arg, Diff): if not isinstance(self.arg, Diff):
...@@ -213,7 +220,7 @@ def expandUsingLinearity(expr, functions=None, constants=None): ...@@ -213,7 +220,7 @@ def expandUsingLinearity(expr, functions=None, constants=None):
if isinstance(expr, Diff): if isinstance(expr, Diff):
arg = expandUsingLinearity(expr.arg, functions) arg = expandUsingLinearity(expr.arg, functions)
if arg.func == sp.Add: if hasattr(arg, 'func') and arg.func == sp.Add:
result = 0 result = 0
for a in arg.args: for a in arg.args:
result += Diff(a, label=expr.label, ceIdx=expr.ceIdx).splitLinear(functions) result += Diff(a, label=expr.label, ceIdx=expr.ceIdx).splitLinear(functions)
......
import sympy as sp
from pystencils.sympyextensions import normalizeProduct
from lbmpy.chapman_enskog.derivative import Diff, DiffOperator, expandUsingLinearity, normalizeDiffOrder
from lbmpy.chapman_enskog.chapman_enskog import expandedSymbol, useChapmanEnskogAnsatz
class SteadyStateChapmanEnskogAnalysis(object):
def __init__(self, method, forceModelClass=None, order=4):
self.method = method
self.dim = method.dim
self.order = order
self.physicalVariables = list(sp.Matrix(self.method.momentEquilibriumValues).atoms(sp.Symbol)) # rho, u..
self.eps = sp.Symbol("epsilon")
self.fSym = sp.Symbol("f", commutative=False)
self.fSyms = [expandedSymbol("f", superscript=i, commutative=False) for i in range(order + 1)]
self.collisionOpSym = sp.Symbol("A", commutative=False)
self.forceSym = sp.Symbol("F_q", commutative=False)
self.velocitySyms = sp.Matrix([expandedSymbol("c", subscript=i, commutative=False) for i in range(self.dim)])
self.F_q = [0] * len(self.method.stencil)
self.forceModel = None
if forceModelClass:
accelerationSymbols = sp.symbols("a_:%d" % (self.dim,), commutative=False)
self.physicalVariables += accelerationSymbols
self.forceModel = forceModelClass(accelerationSymbols)
self.F_q = self.forceModel(self.method)
# Perform the analysis
self.tayloredEquation = self._createTaylorExpandedEquation()
self.pdfHierarchy = self._createPdfHierarchy(self.tayloredEquation)
self.recombinedEq = self._recombinePdfs(self.pdfHierarchy)
symbolsToValues = self._getSymbolsToValuesDict()
self.continuityEquation = self._computeContinuityEquation(self.recombinedEq, symbolsToValues)
self.momentumEquations = [self._computeMomentumEquation(self.recombinedEq, symbolsToValues, h)
for h in range(self.dim)]
def _createTaylorExpandedEquation(self):
"""
Creates a generic, Taylor expanded lattice Boltzmann update equation with collision and force term.
Collision operator and force terms are represented symbolically.
"""
c = self.velocitySyms
Dx = sp.Matrix([DiffOperator(label=l) for l in range(self.dim)])
differentialOperator = sum((self.eps * c.dot(Dx)) ** n / sp.factorial(n)
for n in range(1, self.order + 1))
taylorExpansion = DiffOperator.apply(differentialOperator.expand(), self.fSym)
fNonEq = self.fSym - self.fSyms[0]
return taylorExpansion + self.collisionOpSym * fNonEq - self.eps * self.forceSym
def _createPdfHierarchy(self, tayloredEquation):
"""
Expresses the expanded pdfs f^1, f^2, .. as functions of the equilibrium f^0.
Returns a list where element [1] is the equation for f^1 etc.
"""
chapmanEnskogHierarchy = useChapmanEnskogAnsatz(tayloredEquation, spatialDerivativeOrders=None,
pdfs=(['f', 0, self.order + 1],), commutative=False)
chapmanEnskogHierarchy = [chapmanEnskogHierarchy[i] for i in range(self.order + 1)]
result = []
substitutionDict = {}
for ceEq, f_i in zip(chapmanEnskogHierarchy, self.fSyms):
newEq = -1 / self.collisionOpSym * (ceEq - self.collisionOpSym * f_i)
newEq = expandUsingLinearity(newEq.subs(substitutionDict), functions=self.fSyms + [self.forceSym])
if newEq:
substitutionDict[f_i] = newEq
result.append(newEq)
return result
def _recombinePdfs(self, pdfHierarchy):
return sum(pdfHierarchy[i] * self.eps**(i-1) for i in range(1, self.order+1))
def _computeContinuityEquation(self, recombinedEq, symbolsToValues):
return self._computeMoments(recombinedEq, symbolsToValues)
def _computeMomentumEquation(self, recombinedEq, symbolsToValues, coordinate):
eq = sp.expand(self.velocitySyms[coordinate] * recombinedEq)
result = self._computeMoments(eq, symbolsToValues)
if self.forceModel and hasattr(self.forceModel, 'equilibriumVelocityShift'):
compressible = self.method.conservedQuantityComputation.compressible
shift = self.forceModel.equilibriumVelocityShift(sp.Symbol("rho") if compressible else 1)
result += shift[coordinate]
return result
def _getSymbolsToValuesDict(self):
result = {1 / self.collisionOpSym: self.method.inverseCollisionMatrix,
self.forceSym: sp.Matrix(self.forceModel(self.method)) if self.forceModel else 0,
self.fSyms[0]: self.method.getEquilibriumTerms()}
for i, c_i in enumerate(self.velocitySyms):
result[c_i] = sp.Matrix([d[i] for d in self.method.stencil])
return result
def _computeMoments(self, recombinedEq, symbolsToValues):
eq = recombinedEq.expand()
assert eq.func is sp.Add
newProducts = []
for product in eq.args:
assert product.func is sp.Mul
derivative = None
newProd = 1
for arg in reversed(normalizeProduct(product)):
if isinstance(arg, Diff):
assert derivative is None, "More than one derivative term in the product"
derivative = arg
arg = arg.getArgRecursive() # new argument is inner part of derivative
if arg in symbolsToValues:
arg = symbolsToValues[arg]
haveShape = hasattr(arg, 'shape') and hasattr(newProd, 'shape')
if haveShape and arg.shape == newProd.shape and arg.shape[1] == 1:
newProd = sp.matrix_multiply_elementwise(newProd, arg)
else:
newProd = arg * newProd
newProd = sp.expand(sum(newProd))
if derivative is not None:
newProd = derivative.changeArgRecursive(newProd)
newProducts.append(newProd)
return normalizeDiffOrder(expandUsingLinearity(sp.Add(*newProducts), functions=self.physicalVariables))
if __name__ == '__main__':
from lbmpy.creationfunctions import createLatticeBoltzmannMethod
from lbmpy.forcemodels import Buick
method = createLatticeBoltzmannMethod(stencil='D2Q9', method='srt')
result = SteadyStateChapmanEnskogAnalysis(method, Buick, 3)
...@@ -93,6 +93,10 @@ class DensityVelocityComputation(AbstractConservedQuantityComputation): ...@@ -93,6 +93,10 @@ class DensityVelocityComputation(AbstractConservedQuantityComputation):
return {'density': 1, return {'density': 1,
'velocity': len(self._stencil[0])} 'velocity': len(self._stencil[0])}
@property
def compressible(self):
return self._compressible
def definedSymbols(self, order='all'): def definedSymbols(self, order='all'):
if order == 'all': if order == 'all':
return {'density': self._symbolOrder0, return {'density': self._symbolOrder0,
......
...@@ -110,6 +110,18 @@ class MomentBasedLbMethod(AbstractLbMethod): ...@@ -110,6 +110,18 @@ class MomentBasedLbMethod(AbstractLbMethod):
newEntry = RelaxationInfo(prevEntry[0], relaxationRate) newEntry = RelaxationInfo(prevEntry[0], relaxationRate)
self._momentToRelaxationInfoDict[e] = newEntry self._momentToRelaxationInfoDict[e] = newEntry
@property
def collisionMatrix(self):
M = self.momentMatrix
D = sp.diag(*self.relaxationRates)
return M.inv() * D * M
@property
def inverseCollisionMatrix(self):
M = self.momentMatrix
Dinv = sp.diag(*[1/e for e in self.relaxationRates])
return M.inv() * Dinv * M
@property @property
def momentMatrix(self): def momentMatrix(self):
return momentMatrix(self.moments, self.stencil) return momentMatrix(self.moments, self.stencil)
......
import sympy as sp
import numpy as np import numpy as np
import numbers import numbers
import waLBerla as wlb import waLBerla as wlb
...@@ -7,7 +6,6 @@ from lbmpy.creationfunctions import createLatticeBoltzmannFunction, updateWithDe ...@@ -7,7 +6,6 @@ from lbmpy.creationfunctions import createLatticeBoltzmannFunction, updateWithDe
from lbmpy.macroscopic_value_kernels import compileMacroscopicValuesGetter, compileMacroscopicValuesSetter from lbmpy.macroscopic_value_kernels import compileMacroscopicValuesGetter, compileMacroscopicValuesSetter
from lbmpy.parallel.boundaryhandling import BoundaryHandling from lbmpy.parallel.boundaryhandling import BoundaryHandling
from lbmpy.parallel.blockiteration import slicedBlockIteration from lbmpy.parallel.blockiteration import slicedBlockIteration
from pystencils.field import createNumpyArrayWithLayout, getLayoutOfArray
class Scenario(object): class Scenario(object):
...@@ -38,7 +36,7 @@ class Scenario(object): ...@@ -38,7 +36,7 @@ class Scenario(object):
switchToSymbolicRelaxationRatesForEntropicMethods(methodParameters, kernelParams) switchToSymbolicRelaxationRatesForEntropicMethods(methodParameters, kernelParams)
methodParameters['optimizationParams'] = optimizationParams methodParameters['optimizationParams'] = optimizationParams
self._lbmKernel = createLatticeBoltzmannFunction(**methodParameters) self._lbmKernel = createLatticeBoltzmannFunction(**methodParameters)
else: else:for
self._lbmKernel = lbmKernel self._lbmKernel = lbmKernel
# ----- Add fields # ----- Add fields
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment