From ad5a4d9bf84cf6ff0ce9e5e996a10e840df39fd0 Mon Sep 17 00:00:00 2001
From: Martin Bauer <martin.bauer@fau.de>
Date: Wed, 26 Jul 2017 13:10:47 +0200
Subject: [PATCH] lbmpy: new parameters for input and output of macroscopic
 quantities

- write out macroscopic quantities to field, directly from sweep
- use velocity from field ( for Advection-Diffusion schemes )
---
 creationfunctions.py                    | 24 +++++++++++++++++++++++-
 methods/conservedquantitycomputation.py | 17 ++++++++++++++---
 methods/creationfunctions.py            |  2 +-
 3 files changed, 38 insertions(+), 5 deletions(-)

diff --git a/creationfunctions.py b/creationfunctions.py
index 35b5cea7..c6152bca 100644
--- a/creationfunctions.py
+++ b/creationfunctions.py
@@ -50,6 +50,9 @@ General:
 - ``initialVelocity=None``: initial velocity in domain, can either be a tuple (x,y,z) velocity to set a constant
   velocity everywhere, or a numpy array with the same size of the domain, with a last coordinate of shape dim to set
   velocities on cell level
+- ``output={}``: a dictionary mapping macroscopic quantites e.g. the strings 'density' and 'velocity' to pystencils
+                fields. In each timestep the corresponding quantities are written to the given fields.
+- ``velocityInput``: symbolic field where the velocities are read from (for advection diffusion LBM)
 
 Entropic methods:
 
@@ -151,6 +154,7 @@ from lbmpy.stencils import getStencil
 import lbmpy.forcemodels as forceModels
 from lbmpy.simplificationfactory import createSimplificationStrategy
 from lbmpy.updatekernels import createStreamPullKernel, createPdfArray
+from pystencils.equationcollection.equationcollection import EquationCollection
 
 
 def updateWithDefaultParameters(params, optParams, failOnUnknownParameter=True):
@@ -171,6 +175,9 @@ def updateWithDefaultParameters(params, optParams, failOnUnknownParameter=True):
         'entropic': False,
         'entropicNewtonIterations': None,
         'omegaOutputField': None,
+
+        'output': {},
+        'velocityInput': None,
     }
 
     defaultOptimizationDescription = {
@@ -305,7 +312,22 @@ def createLatticeBoltzmannUpdateRule(lbMethod=None, optimizationParams={}, **kwa
     doCseInOpposingDirections = False if dirCSE not in optParams else optParams[dirCSE]
     doOverallCse = False if 'doOverallCse' not in optParams else optParams['doOverallCse']
     simplification = createSimplificationStrategy(lbMethod, doCseInOpposingDirections, doOverallCse, splitInnerLoop)
-    collisionRule = simplification(lbMethod.getCollisionRule())
+    cqc = lbMethod.conservedQuantityComputation
+
+    if params['velocityInput'] is not None:
+        eqs = [sp.Eq(cqc.zerothOrderMomentSymbol, sum(lbMethod.preCollisionPdfSymbols))]
+        velocityField = params['velocityInput']
+        eqs += [sp.Eq(uSym, velocityField(i)) for i, uSym in enumerate(cqc.firstOrderMomentSymbols)]
+        eqs = EquationCollection(eqs, [])
+        collisionRule = lbMethod.getCollisionRule(conservedQuantityEquations=eqs)
+    else:
+        collisionRule = lbMethod.getCollisionRule()
+
+    if params['output']:
+        outputEqs = cqc.outputEquationsFromPdfs(lbMethod.preCollisionPdfSymbols, params['output'])
+        collisionRule = collisionRule.merge(outputEqs)
+
+    collisionRule = simplification(collisionRule)
 
     if params['entropic']:
         if params['entropicNewtonIterations']:
diff --git a/methods/conservedquantitycomputation.py b/methods/conservedquantitycomputation.py
index 60ff2c6d..e6c04922 100644
--- a/methods/conservedquantitycomputation.py
+++ b/methods/conservedquantitycomputation.py
@@ -3,6 +3,7 @@ from collections import OrderedDict
 
 import sympy as sp
 from pystencils.equationcollection import EquationCollection
+from pystencils.field import Field
 
 
 class AbstractConservedQuantityComputation(abc.ABCMeta('ABC', (object,), {})):
@@ -132,11 +133,12 @@ class DensityVelocityComputation(AbstractConservedQuantityComputation):
         eqColl = applyForceModelShift('equilibriumVelocityShift', dim, eqColl, self._forceModel, self._compressible)
         return eqColl
 
-    def equilibriumInputEquationsFromInitValues(self, density=1, velocity=[0, 0, 0]):
+    def equilibriumInputEquationsFromInitValues(self, density=1, velocity=(0, 0, 0)):
         dim = len(self._stencil[0])
         zerothOrderMoment = density
         firstOrderMoments = velocity[:dim]
         velOffset = [0] * dim
+
         if self._compressible:
             if self._forceModel and hasattr(self._forceModel, 'macroscopicVelocityShift'):
                 velOffset = self._forceModel.macroscopicVelocityShift(zerothOrderMoment)
@@ -144,10 +146,14 @@ class DensityVelocityComputation(AbstractConservedQuantityComputation):
             if self._forceModel and hasattr(self._forceModel, 'macroscopicVelocityShift'):
                 velOffset = self._forceModel.macroscopicVelocityShift(sp.Rational(1, 1))
             zerothOrderMoment -= sp.Rational(1, 1)
+        eqs = [sp.Eq(self._symbolOrder0, zerothOrderMoment)]
+
         firstOrderMoments = [a - b for a, b in zip(firstOrderMoments, velOffset)]
+        if self._compressible:
+            eqs += [sp.expand(sp.Eq(l, r * density)) for l, r in zip(self._symbolsOrder1, firstOrderMoments)]
+        else:
+            eqs += [sp.Eq(l, r) for l, r in zip(self._symbolsOrder1, firstOrderMoments)]
 
-        eqs = [sp.Eq(self._symbolOrder0, zerothOrderMoment)]
-        eqs += [sp.Eq(l, r) for l, r in zip(self._symbolsOrder1, firstOrderMoments)]
         return EquationCollection(eqs, [])
 
     def outputEquationsFromPdfs(self, pdfs, outputQuantityNamesToSymbols):
@@ -167,6 +173,8 @@ class DensityVelocityComputation(AbstractConservedQuantityComputation):
 
         if 'density' in outputQuantityNamesToSymbols:
             densityOutputSymbol = outputQuantityNamesToSymbols['density']
+            if isinstance(densityOutputSymbol, Field):
+                densityOutputSymbol = densityOutputSymbol()
             if densityOutputSymbol != self._symbolOrder0:
                 mainEquations.append(sp.Eq(densityOutputSymbol, self._symbolOrder0))
             else:
@@ -174,6 +182,9 @@ class DensityVelocityComputation(AbstractConservedQuantityComputation):
                 del eqs[self._symbolOrder0]
         if 'velocity' in outputQuantityNamesToSymbols:
             velOutputSymbols = outputQuantityNamesToSymbols['velocity']
+            if isinstance(velOutputSymbols, Field):
+                field = velOutputSymbols
+                velOutputSymbols = [field(i) for i in range(len(self._symbolsOrder1))]
             if tuple(velOutputSymbols) != tuple(self._symbolsOrder1):
                 mainEquations += [sp.Eq(a, b) for a, b in zip(velOutputSymbols, self._symbolsOrder1)]
             else:
diff --git a/methods/creationfunctions.py b/methods/creationfunctions.py
index 9b5e2bfb..0e8d0647 100644
--- a/methods/creationfunctions.py
+++ b/methods/creationfunctions.py
@@ -129,7 +129,7 @@ def createFromEquilibrium(stencil, equilibrium, momentToRelaxationRateDict, comp
     assert len(momToRrDict) == len(stencil), "The number of moments has to be the same as the number of stencil entries"
     densityVelocityComputation = DensityVelocityComputation(stencil, compressible, forceModel)
 
-    rrDict = OrderedDict([(mom, RelaxationInfo(discreteMoment(equilibrium, mom, stencil), rr))
+    rrDict = OrderedDict([(mom, RelaxationInfo(discreteMoment(equilibrium, mom, stencil).expand(), rr))
                           for mom, rr in zip(momToRrDict.keys(), momToRrDict.values())])
     return MomentBasedLbMethod(stencil, rrDict, densityVelocityComputation, forceModel)
 
-- 
GitLab