Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
Markus Holzer
lbmpy
Commits
a3556a10
Commit
a3556a10
authored
May 24, 2017
by
Martin Bauer
Browse files
Automatic Chapman Enskog Analysis of moment-based methods
parent
9d35ef5d
Changes
14
Expand all
Hide whitespace changes
Inline
Side-by-side
chapman_enskog/ChapmanEnskog-MultiDim.ipynb
0 → 100644
View file @
a3556a10
This diff is collapsed.
Click to expand it.
chapman_enskog/ChapmanEnskog.ipynb
0 → 100644
View file @
a3556a10
%% Cell type:code id: tags:
```
python
import
sympy
as
sp
# Using operator and kets from quantum module to represent differential operators and pdfs
from
sympy.physics.quantum
import
Ket
as
Func
from
sympy.physics.quantum
import
Operator
# Disable Ket notation |f> for functions
Func
.
lbracket_latex
=
''
Func
.
rbracket_latex
=
''
sp
.
init_printing
()
```
%% Cell type:markdown id: tags:
# Chapman Enskog analysis
Particle distribution function $f$:
%% Cell type:code id: tags:
```
python
c
=
sp
.
Symbol
(
"c_x"
)
dt
=
sp
.
Symbol
(
"Delta_t"
)
t
=
sp
.
symbols
(
"t"
)
f
=
Func
(
"f"
)
C
=
Func
(
"C"
)
```
%% Cell type:markdown id: tags:
Differential operators (defined simply as non-commutative symbols here)
%% Cell type:code id: tags:
```
python
Dx
=
Operator
(
"\partial_x"
)
Dt
=
Operator
(
"\partial_t"
)
```
%% Cell type:code id: tags:
```
python
taylorOrder
=
2
taylorOperator
=
sum
(
dt
**
k
*
(
Dt
+
c
*
Dx
)
**
k
/
sp
.
functions
.
factorial
(
k
)
for
k
in
range
(
1
,
taylorOrder
+
1
))
taylorOperator
```
%%%% Output: execute_result

$$\frac{\Delta_{t}^{2}}{2} \left(c_{x} \partial_x + \partial_t\right)^{2} + \Delta_{t} \left(c_{x} \partial_x + \partial_t\right)$$
2 2
Δₜ ⋅(cₓ⋅\partialₓ + \partialₜ)
─────────────────────────────── + Δₜ⋅(cₓ⋅\partialₓ + \partialₜ)
2
%% Cell type:markdown id: tags:
As right-hand-side we use the abstract collision operator $C$, which corresponds to (4.5)
%% Cell type:code id: tags:
```
python
eq_4_5
=
(
taylorOperator
*
f
)
-
C
eq_4_5
```
%%%% Output: execute_result

$$\left(\frac{\Delta_{t}^{2}}{2} \left(c_{x} \partial_x + \partial_t\right)^{2} + \Delta_{t} \left(c_{x} \partial_x + \partial_t\right)\right) {f} - {C}$$
⎛ 2 2 ⎞
⎜Δₜ ⋅(cₓ⋅\partialₓ + \partialₜ) ⎟
⎜─────────────────────────────── + Δₜ⋅(cₓ⋅\partialₓ + \partialₜ)⎟⋅❘f⟩ - ❘C⟩
⎝ 2 ⎠
%% Cell type:markdown id: tags:
Following the same steps as in the book, getting rid of second derivative, and discarding $
\D
elta_t^3$ we get to (4.7)
%% Cell type:code id: tags:
```
python
eq_4_7
=
eq_4_5
-
(
dt
/
2
)
*
(
Dt
+
c
*
Dx
)
*
eq_4_5
eq_4_7
=
eq_4_7
.
expand
().
subs
(
dt
**
3
,
0
)
eq_4_7
```
%% Cell type:markdown id: tags:
### Chapman Enskog Ansatz
Open Question:
why is not everything expanded equally (derivatives start at 1, spatial terminates one earlier...)
%% Cell type:code id: tags:
```
python
eps
=
sp
.
Symbol
(
"epsilon"
)
ceSymbolsF
=
[
Func
(
"f{}"
.
format
(
i
))
for
i
in
range
(
3
)]
ceSymbolsDt
=
[
Operator
(
"\partial_t^{{ ({}) }}"
.
format
(
i
))
for
i
in
range
(
1
,
3
)]
ceSymbolsDx
=
[
Operator
(
"\partial_x^{{ ({}) }}"
.
format
(
i
))
for
i
in
range
(
1
,
2
)]
ceF
=
sum
(
eps
**
k
*
s
for
k
,
s
in
enumerate
(
ceSymbolsF
,
start
=
0
))
ceDt
=
sum
(
eps
**
k
*
s
for
k
,
s
in
enumerate
(
ceSymbolsDt
,
start
=
1
))
ceDx
=
sum
(
eps
**
k
*
s
for
k
,
s
in
enumerate
(
ceSymbolsDx
,
start
=
1
))
ceSubstitutions
=
{
Dt
:
ceDt
,
Dx
:
ceDx
,
f
:
ceF
}
ceSubstitutions
```
%% Cell type:markdown id: tags:
Inserting the SRT/BGK collision operator
%% Cell type:code id: tags:
```
python
srtC
=
-
dt
/
sp
.
Symbol
(
"tau"
)
*
(
ceF
-
ceSymbolsF
[
0
])
srtC
```
%% Cell type:code id: tags:
```
python
eq_4_7_ce
=
eq_4_7
.
subs
(
ceSubstitutions
).
subs
(
C
,
srtC
).
expand
().
collect
(
eps
)
eq_4_7_ce
```
%% Cell type:code id: tags:
```
python
eq_4_9_a
=
(
eq_4_7_ce
.
coeff
(
eps
)
/
dt
).
expand
()
eq_4_9_a
```
%% Cell type:code id: tags:
```
python
eq_4_9_b
=
(
eq_4_7_ce
.
coeff
(
eps
**
2
)
/
dt
).
expand
()
eq_4_9_b
```
%% Cell type:markdown id: tags:
Computing moments
%% Cell type:code id: tags:
```
python
import
operator
from
functools
import
reduce
def
prod
(
factors
):
return
reduce
(
operator
.
mul
,
factors
,
1
)
def
getMomentSymbol
(
idx
,
order
):
momentOrderStr
=
[
'alpha'
,
'beta'
,
'gamma'
,
'delta'
]
momentOrderStr
=
"_"
.
join
(
momentOrderStr
[:
order
-
1
]
+
[
'x'
])
return
sp
.
Symbol
(
"Pi^(%d)_%s"
%
(
idx
,
momentOrderStr
),
commutative
=
False
)
def
takeMoments
(
eqn
,
order
):
markerTerms
=
sp
.
symbols
(
"c_alpha c_beta c_gamma c_delta"
)
velocityTermSet
=
set
(
markerTerms
)
velocityTermSet
.
add
(
c
)
factor
=
prod
(
markerTerms
[:
order
])
eqn
=
(
eqn
*
factor
).
expand
()
result
=
0
for
fac
in
eqn
.
args
:
occuringFs
=
list
(
fac
.
atoms
(
Func
))
assert
len
(
occuringFs
)
<
2
if
len
(
occuringFs
)
==
0
:
result
+=
fac
continue
fIdx
=
ceSymbolsF
.
index
(
occuringFs
[
0
])
occuringCs
=
fac
.
atoms
(
sp
.
Symbol
).
intersection
(
velocityTermSet
)
facWithoutCs
=
sp
.
cancel
(
fac
/
prod
(
occuringCs
)
/
occuringFs
[
0
])
assert
not
facWithoutCs
.
atoms
(
sp
.
Symbol
).
intersection
(
velocityTermSet
),
"Non-linear velocity term"
# TODO handle multiple non-marker terms
moment
=
getMomentSymbol
(
fIdx
,
len
(
occuringCs
))
#momentOrderStr = ['alpha', 'beta', 'gamma', 'delta']
#momentOrderStr = "_".join(momentOrderStr[:len(occuringCs)])
#moment = sp.Symbol("Pi^(%d)_%s" % (fIdx, momentOrderStr), commutative=False)
result
+=
facWithoutCs
*
moment
return
result
```
%% Cell type:code id: tags:
```
python
rho
=
Func
(
"rho"
)
u_x
=
Func
(
"u_x"
)
momentReplacements
=
{
getMomentSymbol
(
0
,
0
):
rho
,
getMomentSymbol
(
0
,
1
):
rho
*
u_x
,
getMomentSymbol
(
1
,
0
):
0
,
# According to eq 4.4
getMomentSymbol
(
1
,
1
):
0
,
getMomentSymbol
(
2
,
0
):
0
,
getMomentSymbol
(
2
,
1
):
0
,
}
momentReplacements
```
%% Cell type:markdown id: tags:
### Moments
Moments of $
\e
psilon$-sorted equations
$O(
\e
psilon)$
%% Cell type:code id: tags:
```
python
eq_4_10_a
=
takeMoments
(
eq_4_9_a
,
0
).
subs
(
momentReplacements
)
eq_4_10_a
```
%% Cell type:code id: tags:
```
python
eq_4_10_b
=
takeMoments
(
eq_4_9_a
,
1
).
subs
(
momentReplacements
)
eq_4_10_b
```
%% Cell type:code id: tags:
```
python
eq_4_10_c
=
takeMoments
(
eq_4_9_a
,
2
).
subs
(
momentReplacements
)
eq_4_10_c
```
%% Cell type:markdown id: tags:
$O(
\e
psilon^2)$
%% Cell type:code id: tags:
```
python
eq_4_12_a
=
takeMoments
(
eq_4_9_b
,
0
).
subs
(
momentReplacements
)
eq_4_12_a
```
%% Cell type:code id: tags:
```
python
eq_4_12_b
=
takeMoments
(
eq_4_9_b
,
1
).
subs
(
momentReplacements
)
eq_4_12_b
```
%% Cell type:markdown id: tags:
Recombination
%% Cell type:code id: tags:
```
python
(
eps
*
eq_4_10_a
+
eps
**
2
*
eq_4_12_a
).
expand
()
```
%% Cell type:code id: tags:
```
python
(
eps
*
eq_4_10_b
+
eps
**
2
*
eq_4_12_b
).
expand
()
```
%% Cell type:code id: tags:
```
python
stressTensorSubs
=
-
```
%% Cell type:code id: tags:
```
python
from
lbmpy.maxwellian_equilibrium
import
getMomentsOfDiscreteMaxwellianEquilibrium
from
lbmpy.stencils
import
getStencil
from
lbmpy.moments
import
momentsOfOrder
stencil
=
getStencil
(
"D3Q19"
)
dim
=
len
(
stencil
[
0
])
moments
=
tuple
(
momentsOfOrder
(
2
,
dim
=
dim
))
print
(
moments
)
u
=
Func
(
"u_x"
),
Func
(
"u_y"
),
Func
(
"u_z"
)
rho
=
Func
(
"rho"
)
pi_ab
=
getMomentsOfDiscreteMaxwellianEquilibrium
(
stencil
,
moments
,
c_s_sq
=
sp
.
Rational
(
1
,
3
),
order
=
2
,
u
=
u
,
rho
=
rho
)
pi_ab
```
%% Cell type:code id: tags:
```
python
from
lbmpy.maxwellian_equilibrium
import
getMomentsOfContinuousMaxwellianEquilibrium
pi_ab2
=
getMomentsOfContinuousMaxwellianEquilibrium
(
moments
,
dim
,
c_s_sq
=
sp
.
Rational
(
1
,
3
),
order
=
2
)
pi_ab2
```
%% Cell type:code id: tags:
```
python
sp
.
solve
(
eq_4_10_c
,
getMomentSymbol
(
1
,
2
))[
0
]
```
%% Cell type:code id: tags:
```
python
from
lbmpy.chapman_enskog
import
*
productRule
((
ceSymbolsDt
[
0
]
*
pi_ab
[
1
]).
expand
())
```
%% Cell type:code id: tags:
```
python
dtSubsDict
=
{
ceSymbolsDt
[
0
]
*
rho
:
-
ceSymbolsDx
[
0
]
*
(
rho
*
u
[
0
]),
productRule
((
ceSymbolsDt
[
0
]
*
(
rho
*
u
[
1
])).
expand
())
:
sp
.
Symbol
(
"bla"
)
}
dtSubsDict
```
%% Cell type:code id: tags:
```
python
-
ceSymbolsDx
[
0
]
*
(
rho
*
u
[
0
])
```
%% Cell type:code id: tags:
```
python
```
chapman_enskog/ChapmanEnskogNewDerivativeObjects.ipynb
0 → 100644
View file @
a3556a10
This diff is collapsed.
Click to expand it.
chapman_enskog/ChapmanEnskogUsingLbmpy.ipynb
0 → 100644
View file @
a3556a10
This diff is collapsed.
Click to expand it.
chapman_enskog/__init__.py
0 → 100644
View file @
a3556a10
from
lbmpy.chapman_enskog.derivative
import
DiffOperator
,
Diff
,
expandUsingLinearity
,
expandUsingProductRule
,
\
normalizeDiffOrder
,
chapmanEnskogDerivativeExpansion
,
chapmanEnskogDerivativeRecombination
from
lbmpy.chapman_enskog.chapman_enskog
import
getExpandedName
,
LbMethodEqMoments
,
insertMoments
,
takeMoments
,
\
CeMoment
,
chainSolveAndSubstitute
,
timeDiffSelector
,
momentSelector
chapman_enskog/chapman_enskog.py
0 → 100644
View file @
a3556a10
This diff is collapsed.
Click to expand it.
chapman_enskog/chapman_enskog_old.py
0 → 100644
View file @
a3556a10
import
sympy
as
sp
from
sympy.physics.quantum
import
Ket
as
Func
from
sympy.physics.quantum
import
Operator
from
functools
import
reduce
import
operator
# Disable Ket notation |f> for functions
Func
.
lbracket_latex
=
''
Func
.
rbracket_latex
=
''
def
prod
(
seq
):
return
reduce
(
operator
.
mul
,
seq
,
1
)
def
allIn
(
a
,
b
):
"""Tests if all elements of a are contained in b"""
return
all
(
element
in
b
for
element
in
a
)
def
isDerivative
(
term
):
return
isinstance
(
term
,
Operator
)
and
term
.
args
[
0
].
name
.
startswith
(
"
\\
partial"
)
def
getDiffOperator
(
subscript
,
superscript
=
None
):
symbolName
=
"\partial_"
+
subscript
if
superscript
:
symbolName
+=
"^"
+
superscript
return
Operator
(
symbolName
)
def
normalizeProduct
(
prod
):
"""Takes a sympy Mul node and returns a list of factors (with Pow nodes resolved)"""
def
handlePow
(
pow
):
if
pow
.
exp
.
is_integer
and
pow
.
exp
.
is_number
and
pow
.
exp
>
0
:
return
[
pow
.
base
]
*
pow
.
exp
else
:
return
[
pow
]
if
prod
.
func
==
sp
.
Symbol
or
prod
.
func
==
Func
:
return
[
prod
]
if
prod
.
func
==
sp
.
Pow
:
return
handlePow
(
prod
)
assert
prod
.
func
==
sp
.
Mul
result
=
[]
for
a
in
prod
.
args
:
if
a
.
func
==
sp
.
Pow
:
result
+=
handlePow
(
a
)
else
:
result
.
append
(
a
)
return
result
def
splitDerivativeProd
(
expr
):
"""Splits a term a b \partial c d into three parts: functions before operator (here a b),
the operator itself, and terms the operator acts on (here c d). If the passed expressions does
not have above form, None is returned"""
productArgs
=
normalizeProduct
(
expr
)
argumentsActedOn
=
[]
remainingArguments
=
[]
derivOp
=
None
for
t
in
reversed
(
productArgs
):
if
isDerivative
(
t
)
and
derivOp
is
None
:
derivOp
=
t
elif
derivOp
is
None
:
argumentsActedOn
.
append
(
t
)
else
:
remainingArguments
.
append
(
t
)
if
derivOp
is
None
:
return
None
return
list
(
reversed
(
remainingArguments
)),
derivOp
,
argumentsActedOn
def
getName
(
obj
):
if
type
(
obj
)
in
[
Operator
,
Func
]:
return
obj
.
args
[
0
].
name
else
:
return
obj
.
name
def
combineDerivatives
(
expr
):
from
collections
import
defaultdict
def
searchAndCombine
(
termList
):
if
len
(
termList
)
<=
1
:
return
termList
,
False
newTermList
=
[]
handledIdxSet
=
set
()
changes
=
False
for
i
in
range
(
len
(
termList
)):
if
i
in
handledIdxSet
:
continue
for
j
in
range
(
i
+
1
,
len
(
termList
)):
pre1
,
post1
=
termList
[
i
]
pre2
,
post2
=
termList
[
j
]
rest1
=
[
item
for
item
in
pre1
if
item
not
in
post2
]
rest2
=
[
item
for
item
in
pre2
if
item
not
in
post1
]
restEqual
=
(
len
(
rest1
)
==
len
(
rest2
))
and
(
set
(
rest1
)
==
set
(
rest2
))
if
allIn
(
post1
,
pre2
)
and
allIn
(
post2
,
pre1
)
and
restEqual
:
handledIdxSet
.
add
(
j
)
newTermList
.
append
((
rest1
,
post1
+
post2
))
changes
=
True
break
else
:
newTermList
.
append
(
termList
[
i
])
lastIdx
=
len
(
termList
)
-
1
if
lastIdx
not
in
handledIdxSet
:
newTermList
.
append
(
termList
[
lastIdx
])
return
newTermList
,
changes
expr
=
expr
.
expand
()
if
expr
.
func
!=
sp
.
Add
:
return
expr
operatorDict
=
defaultdict
(
list
)
# maps the operator to a list of tuples with terms before and after the operator
result
=
0
for
term
in
expr
.
args
:
splitted
=
splitDerivativeProd
(
term
)
if
splitted
:
pre
,
op
,
post
=
splitted
operatorDict
[
op
].
append
((
pre
,
post
))
else
:
result
+=
term
for
op
,
termList
in
operatorDict
.
items
():
newTermList
,
changes
=
searchAndCombine
(
termList
)
while
changes
:
newTermList
,
changes
=
searchAndCombine
(
newTermList
)
for
pre
,
post
in
newTermList
:
result
+=
prod
(
pre
)
*
op
*
prod
(
post
)
return
result
def
expandDerivatives
(
expr
):
"""Fully expands all derivatives by applying product rule"""
def
handleProduct
(
term
):
splittedTerm
=
splitDerivativeProd
(
term
)
if
splittedTerm
is
None
:
return
term
remainingArguments
,
derivOp
,
argumentsActedOn
=
splittedTerm
result
=
0
for
i
in
range
(
len
(
argumentsActedOn
)):
beforeOp
=
prod
([
argumentsActedOn
[
j
]
for
j
in
range
(
len
(
argumentsActedOn
))
if
j
!=
i
])
result
+=
beforeOp
*
derivOp
*
argumentsActedOn
[
i
]
return
prod
(
remainingArguments
)
*
result
expr
=
expr
.
expand
()
if
expr
.
func
!=
sp
.
Add
:
return
handleProduct
(
expr
)
else
:
return
sum
(
handleProduct
(
t
)
for
t
in
expr
.
args
)
def
commuteTerms
(
expr
):
def
commute
(
term
):
forward
=
{
obj
:
sp
.
Symbol
(
getName
(
obj
))
for
obj
in
term
.
atoms
(
Func
)}
backward
=
{
sp
.
Symbol
(
getName
(
obj
)):
obj
for
obj
in
term
.
atoms
(
Func
)}
return
term
.
subs
(
forward
).
subs
(
backward
)
def
handleProduct
(
term
):
splittedTerm
=
splitDerivativeProd
(
term
)
if
splittedTerm
is
None
:
return
term
remainingArguments
,
derivOp
,
argumentsActedOn
=
splittedTerm
return
commute
(
prod
(
remainingArguments
))
*
derivOp
*
commute
(
prod
(
argumentsActedOn
))
expr
=
expr
.
expand
()
if
expr
.
func
!=
sp
.
Add
:
return
handleProduct
(
expr
)
else
:
return
sum
(
handleProduct
(
t
)
for
t
in
expr
.
args
)
#def splitDerivativeTerm(term):
# if term.func == sp.Mul:
# derivativeIdx = [i for i, arg in enumerate(term.args) if isDerivative(arg)]
# if len(derivativeIdx) > 0:
# idx = derivativeIdx[-1]
# diffOperator = term.args[idx]
# assert not diffOperator.is_commutative
# derivedTerms = [t for t in term.args[idx + 1:] if not t.is_commutative]
#
# newDerivedTerms = []
# for t in derivedTerms:
# if t.func == sp.Pow and t.exp.is_integer and t.exp.is_number and 0 < t.exp < 10:
# newDerivedTerms += [t.base] * t.exp
# else:
# newDerivedTerms.append(t)
# derivedTerms = newDerivedTerms
#
# notDerivedTerms = list(term.args[:idx]) + [t for t in term.args[idx + 1:] if t.is_commutative]
# return diffOperator, notDerivedTerms, derivedTerms
# return None, [], []
#
#
#def productRule(expr):
# """
# Applies product rule to terms with differential operator(s)
# :param expr: sympy expression to apply product rule to
# :return:
# """
# def visit(term):
# diffOperator, notDerivedTerms, derivedTerms = splitDerivativeTerm(term)
# if len(derivedTerms) > 1:
# result = 0
# for i in range(len(derivedTerms)):
# beforeOperator = [t for j, t in enumerate(derivedTerms) if j != i]
# result += prod(notDerivedTerms + beforeOperator + [diffOperator, derivedTerms[i]])
# return result
#
# return term if not term.args else term.func(*[visit(a) for a in term.args])
#
# return visit(expr)
#
#
#def substituteDerivative(expr, diffOperatorToSearch, termsToSearch, substitution):
# def visit(term):
# diffOperator, notDerivedTerms, derivedTerms = splitDerivativeTerm(term)
# if diffOperator == diffOperatorToSearch:
# termMatches = True
# for innerTerm in termsToSearch:
# if innerTerm not in notDerivedTerms and innerTerm not in derivedTerms:
# termMatches = False
# break
# if termMatches:
# pass
#
# if len(derivedTerms) > 1:
# result = 0
# for i in range(len(derivedTerms)):
# beforeOperator = [t for j, t in enumerate(derivedTerms) if j != i]
# result += prod(notDerivedTerms + beforeOperator + [diffOperator, derivedTerms[i]])
# return result
#
# return term if not term.args else term.func(*[visit(a) for a in term.args])
#
# return visit(expr)
#
import
sympy
import
sympy.core
import
sympy
as
sp