Commit a1bb764f authored by Martin Bauer's avatar Martin Bauer
Browse files

started with generalized steady state Chapman Enskog expansion

parent e5dd784b
......@@ -25,12 +25,12 @@ def getExpandedName(originalObject, number):
return originalObject.func(newName)
def expandedSymbol(name, subscript=None, superscript=None):
def expandedSymbol(name, subscript=None, superscript=None, **kwargs):
if subscript is not None:
name += "_{%s}" % (subscript,)
if superscript is not None:
name += "^{(%s)}" % (superscript,)
return sp.Symbol(name)
return sp.Symbol(name, **kwargs)
# -------------------------------- Summation Convention -------------------------------------------------------------
......@@ -383,7 +383,7 @@ def getTaylorExpandedLbEquation(pdfSymbolName="f", pdfsAfterCollisionOperator="\
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")
......@@ -406,9 +406,9 @@ def useChapmanEnskogAnsatz(equation, timeDerivativeOrders=(1, 3), spatialDerivat
for pdfName, startOrder, stopOrder in pdfs:
if isinstance(pdfName, sp.Symbol):
pdfName = pdfName.name
expandedPdfSymbols += [expandedSymbol(pdfName, superscript=i) for i in range(startOrder, stopOrder)]
subsDict[sp.Symbol(pdfName)] = sum(eps ** i * 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, **kwargs)] = sum(eps ** i * expandedSymbol(pdfName, superscript=i, **kwargs)
for i in range(startOrder, stopOrder))
maxExpansionOrder = max(maxExpansionOrder, stopOrder)
equation = equation.subs(subsDict)
equation = expandUsingLinearity(equation, functions=expandedPdfSymbols).expand().collect(eps)
......
......@@ -78,7 +78,6 @@ class Diff(sp.Expr):
- all simplifications have to be done manually
- each Diff has a Chapman Enskog expansion order index: 'ceIdx'
"""
is_commutative = True
is_number = False
is_Rational = False
......@@ -87,6 +86,14 @@ class Diff(sp.Expr):
return sp.Rational(0, 1)
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):
"""Returns the argument the derivative acts on, for nested derivatives the inner argument is returned"""
if not isinstance(self.arg, Diff):
......@@ -213,7 +220,7 @@ def expandUsingLinearity(expr, functions=None, constants=None):
if isinstance(expr, Diff):
arg = expandUsingLinearity(expr.arg, functions)
if arg.func == sp.Add:
if hasattr(arg, 'func') and arg.func == sp.Add:
result = 0
for a in arg.args:
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):
return {'density': 1,
'velocity': len(self._stencil[0])}
@property
def compressible(self):
return self._compressible
def definedSymbols(self, order='all'):
if order == 'all':
return {'density': self._symbolOrder0,
......
......@@ -110,6 +110,18 @@ class MomentBasedLbMethod(AbstractLbMethod):
newEntry = RelaxationInfo(prevEntry[0], relaxationRate)
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
def momentMatrix(self):
return momentMatrix(self.moments, self.stencil)
......
import sympy as sp
import numpy as np
import numbers
import waLBerla as wlb
......@@ -7,7 +6,6 @@ from lbmpy.creationfunctions import createLatticeBoltzmannFunction, updateWithDe
from lbmpy.macroscopic_value_kernels import compileMacroscopicValuesGetter, compileMacroscopicValuesSetter
from lbmpy.parallel.boundaryhandling import BoundaryHandling
from lbmpy.parallel.blockiteration import slicedBlockIteration
from pystencils.field import createNumpyArrayWithLayout, getLayoutOfArray
class Scenario(object):
......@@ -38,7 +36,7 @@ class Scenario(object):
switchToSymbolicRelaxationRatesForEntropicMethods(methodParameters, kernelParams)
methodParameters['optimizationParams'] = optimizationParams
self._lbmKernel = createLatticeBoltzmannFunction(**methodParameters)
else:
else:for
self._lbmKernel = lbmKernel
# ----- Add fields
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment