11 Helper class to model a hyperbolic PDE in first-order conservative
14 To model your PDE, you typically run through a couple of single steps.
15 First, include this package plus sympy. Next, create a new instance
16 of this class to which you pass the number of equations in your PDE
17 system, i.e., the number of unknowns you want to develop, plus the
20 As a consequence, the solver holds an equation pde which describes the
21 PDE's right-hand side in the representation
23 \partial Q(t) + div_x F(Q)
25 Most people prefer not to work with a vector Q but with some symbolic
26 names. Feel free to derive them from Q via constructs similar to
29 j = sympy.Array(euler.Q[1:4])
33 def __init__(self, unknowns, auxiliary_variables, dimensions):
34 PDE.__init__(self, unknowns, auxiliary_variables, dimensions)
36 self.
F = sympy.symarray(
"F", (unknowns, dimensions))
37 self.
ncp = sympy.symarray(
"ncp", (unknowns, dimensions))
38 self.
eigenvalues = sympy.symarray(
"alpha", (unknowns, dimensions))
39 self.
sources = sympy.symarray(
"S", (unknowns))
44 result +=
"d_t(" + str(self.
Q[i]) +
"(x)) + div("
45 result += str(self.
F[i])
46 if isinstance(self.
ncp[i], numbers.Number):
48 result += str(self.
ncp[i])
50 if isinstance(self.
sources[i], numbers.Number)
or isinstance(self.
sources[i], sympy.Expr):
51 result += str(self.
sources[i]) +
"\n"
56 result +=
"\\lambda_{max," + str(i) +
"}(x) = "
62 result =
"\\begin{eqnarray*}"
64 result +=
"\\partial _t " + str(self.
Q[i]) +
"(x) + div("
65 for j
in range(0, len(self.
F[i])):
68 result += str(self.
F[i][j])
69 if isinstance(self.
ncp[i], numbers.Number):
71 result += str(self.
ncp[i][j])
73 if isinstance(self.
sources[i], numbers.Number)
or isinstance(self.
sources[i], sympy.Expr):
74 result += str(self.
sources[i]) +
" \\\\"
78 result +=
"\\lambda _{max," + str(i) +
"}(x) & = & ["
84 result +=
"\\end{eqnarray*}"
85 result = result.replace(
"**",
"^")
86 result = result.replace(
"sqrt",
"\\sqrt")
91 Usually used to set a symbolic variable (expression) to a value
92 (new_expression). We run over all internal expressions and set
96 if not isinstance(self.
sources[i], numbers.Number):
99 if not isinstance(self.
F[i, d], numbers.Number):
100 self.
F[i, d] = self.
F[i, d].subs(expression, new_expression)
101 if not isinstance(self.
ncp[i, d], numbers.Number):
102 self.
ncp[i, d] = self.
ncp[i, d].subs(expression, new_expression)
103 if not isinstance(self.
eigenvalues[i, d], numbers.Number):
105 expression, new_expression
110 Return implementation for flux along one coordinate axis (d) as C code.
111 invoke_evalf_before_output: boolean
112 If your expression is a symbolic expression (default) then we use evalf
113 before we pipe it into the output. If your expression is something numeric,
114 then evalf will fail (as it is not defined for scalar quantities).
116 result =
"assertion(normal >= 0);\n"
117 result +=
"assertion(normal < Dimensions);\n"
119 is_cell_mapping=
False
121 result +=
"switch( normal ) {\n"
123 result +=
" case " + str(d) +
":\n"
125 if invoke_evalf_before_output:
126 result += sympy.printing.cxxcode(
127 self.
F[i, d].evalf(), assign_to=
"F[" + str(i) +
"]"
134 + sympy.printing.cxxcode(self.
F[i, d])
138 result +=
"assertion(!std::isnan(F[" + str(i) +
"]));\n"
139 result +=
"nonCriticalAssertion(F[" + str(i) +
"] == F[" + str(i) +
"]);\n"
140 result +=
" break;\n"
146 Return implementation for nonconservative product (ncp) along one coordinate axis (d) as C code.
147 invoke_evalf_before_output: boolean
148 If your expression is a symbolic expression (default) then we use evalf
149 before we pipe it into the output. If your expression is something numeric,
150 then evalf will fail (as it is not defined for scalar quantities).
152 result =
"assertion(normal >= 0);\n"
153 result +=
"assertion(normal < Dimensions);\n"
155 is_cell_mapping=
False, has_delta=
True
157 result +=
"switch( normal ) {\n"
159 result +=
" case " + str(d) +
":\n"
161 if invoke_evalf_before_output:
162 result += sympy.printing.cxxcode(
163 self.
ncp[i, d].evalf(), assign_to=
"BTimesDeltaQ[" + str(i) +
"]"
170 + sympy.printing.cxxcode(self.
ncp[i, d])
174 result +=
" break;\n"
182 This yields a set of eigenvalues, i.e., one per unknown. For many solvers such as
183 Rusanov, you need only one.
186 The axis along which we wanna have the eigenvalues
188 invoke_evalf_before_output: boolean
189 If your expression is a symbolic expression (default) then we use evalf
190 before we pipe it into the output. If your expression is something numeric,
191 then evalf will fail (as it is not defined for scalar quantities).
193 result =
"assertion(normal >= 0);\n"
194 result +=
"assertion(normal < Dimensions);\n"
196 is_cell_mapping=
False
198 result +=
"switch (normal) {\n"
200 result +=
" case " + str(d) +
":\n"
202 if invoke_evalf_before_output:
203 result += sympy.printing.cxxcode(
205 assign_to=
"lambda[" + str(i) +
"]",
216 result +=
" break;\n"
221 self, invoke_evalf_before_output=False, use_absolute_values=True
224 Return maximum eigenvalue
226 result =
"assertion(normal >= 0);\n"
227 result +=
"assertion(normal < Dimensions);\n"
229 is_cell_mapping=
False
232 result +=
"switch (normal) {\n"
234 result +=
" case " + str(d) +
":\n"
236 if invoke_evalf_before_output:
237 result += sympy.printing.cxxcode(
239 assign_to=
"lambda[" + str(i) +
"]",
250 result +=
"assertion(!std::isnan(lambda[" + str(i) +
"]));\n"
251 result +=
" break;\n"
253 result +=
"double result = 0.0;\n"
255 if use_absolute_values:
257 "result = std::max( result, std::abs(lambda[" + str(i) +
"]) );\n"
260 result +=
"result = std::max( result, lambda[" + str(i) +
"] );\n"
261 result +=
"return result;\n"
266 Return implementation for sources as C code.
268 result =
"assertion(normal >= 0);\n"
269 result +=
"assertion(normal < Dimensions);\n"
274 if invoke_evalf_before_output:
275 result += sympy.printing.cxxcode(
276 self.
sources[i].evalf(), assign_to=
"S[" + str(i) +
"]"
283 + sympy.printing.cxxcode(self.
sources[i])
_implementation_of_mapping_onto_named_quantities(self, is_cell_mapping=True, is_boundary=False, has_delta=False)
Return the C code that maps the quantities from Q onto properly labelled quantities.