1
2 """Canned operators for several PDEs, such as Maxwell's, heat, Poisson, etc. (deprecated module)"""
3
4 from __future__ import division
5
6 __copyright__ = "Copyright (C) 2007 Andreas Kloeckner"
7
8 __license__ = """
9 This program is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see U{http://www.gnu.org/licenses/}.
21 """
22
23
24
25
26
27
28
29
30
31
32
33 import numpy
34 import numpy.linalg as la
35 import hedge.tools
36 import hedge.mesh
37 import hedge.data
38 from pytools import memoize_method
39 from hedge.models import Operator, TimeDependentOperator
40
41
42
43
45 """This operator discretizes the Wave equation S{part}tt u = c^2 S{Delta} u.
46
47 To be precise, we discretize the hyperbolic system
48
49 - S{part}t u - c div v = 0
50 - S{part}t v - c grad u = 0
51
52 The sign of M{v} determines whether we discretize the forward or the
53 backward wave equation.
54
55 c is assumed to be constant across all space.
56 """
57
63 assert isinstance(dimensions, int)
64
65 self.c = c
66 self.dimensions = dimensions
67 self.source_f = source_f
68
69 if self.c > 0:
70 self.sign = 1
71 else:
72 self.sign = -1
73
74 self.dirichlet_tag = dirichlet_tag
75 self.neumann_tag = neumann_tag
76 self.radiation_tag = radiation_tag
77
78 self.flux_type = flux_type
79
109
111 from hedge.optemplate import \
112 make_vector_field, \
113 pair_with_boundary, \
114 get_flux_operator, \
115 make_nabla, \
116 InverseMassOperator, \
117 BoundarizeOperator
118
119 d = self.dimensions
120
121 w = make_vector_field("w", d+1)
122 u = w[0]
123 v = w[1:]
124
125
126 from hedge.tools import join_fields
127
128
129
130 dir_u = BoundarizeOperator(self.dirichlet_tag) * u
131 dir_v = BoundarizeOperator(self.dirichlet_tag) * v
132 dir_bc = join_fields(-dir_u, dir_v)
133
134
135 neu_u = BoundarizeOperator(self.neumann_tag) * u
136 neu_v = BoundarizeOperator(self.neumann_tag) * v
137 neu_bc = join_fields(neu_u, -neu_v)
138
139
140 from hedge.optemplate import make_normal
141 rad_normal = make_normal(self.radiation_tag, d)
142
143 rad_u = BoundarizeOperator(self.radiation_tag) * u
144 rad_v = BoundarizeOperator(self.radiation_tag) * v
145
146 rad_bc = join_fields(
147 0.5*(rad_u - self.sign*numpy.dot(rad_normal, rad_v)),
148 0.5*rad_normal*(numpy.dot(rad_normal, rad_v) - self.sign*rad_u)
149 )
150
151
152 nabla = make_nabla(d)
153 flux_op = get_flux_operator(self.flux())
154
155 from hedge.tools import join_fields
156 return (
157 - join_fields(
158 -self.c*numpy.dot(nabla, v),
159 -self.c*(nabla*u)
160 )
161 +
162 InverseMassOperator() * (
163 flux_op*w
164 + flux_op * pair_with_boundary(w, dir_bc, self.dirichlet_tag)
165 + flux_op * pair_with_boundary(w, neu_bc, self.neumann_tag)
166 + flux_op * pair_with_boundary(w, rad_bc, self.radiation_tag)
167 ))
168
169
170 - def bind(self, discr):
171 from hedge.mesh import check_bc_coverage
172 check_bc_coverage(discr.mesh, [
173 self.dirichlet_tag,
174 self.neumann_tag,
175 self.radiation_tag])
176
177 compiled_op_template = discr.compile(self.op_template())
178
179 def rhs(t, w):
180 rhs = compiled_op_template(w=w)
181
182 if self.source_f is not None:
183 rhs[0] += self.source_f(t)
184
185 return rhs
186
187 return rhs
188
191
192
193
194
196 """This operator discretizes the Wave equation S{part}tt u = c^2 S{Delta} u.
197
198 To be precise, we discretize the hyperbolic system
199
200 - S{part}t u - c div v = 0
201 - S{part}t v - c grad u = 0
202 """
203
210 """`c` is assumed to be positive and conforms to the
211 `hedge.data.ITimeDependentGivenFunction` interface.
212
213 `source` also conforms to the
214 `hedge.data.ITimeDependentGivenFunction` interface.
215 """
216 assert isinstance(dimensions, int)
217
218 self.c = c
219 self.time_sign = time_sign
220 self.dimensions = dimensions
221 self.source = source
222
223 self.dirichlet_tag = dirichlet_tag
224 self.neumann_tag = neumann_tag
225 self.radiation_tag = radiation_tag
226
227 self.flux_type = flux_type
228
257
259 from hedge.optemplate import \
260 Field, \
261 make_vector_field, \
262 pair_with_boundary, \
263 get_flux_operator, \
264 make_nabla, \
265 InverseMassOperator, \
266 BoundarizeOperator
267
268 d = self.dimensions
269
270 w = make_vector_field("w", d+1)
271 u = w[0]
272 v = w[1:]
273
274 from hedge.tools import join_fields
275 c = Field("c")
276 flux_w = join_fields(c, w)
277
278
279 from hedge.flux import make_normal
280 normal = make_normal(d)
281
282 from hedge.tools import join_fields
283
284 dir_c = BoundarizeOperator(self.dirichlet_tag) * c
285 dir_u = BoundarizeOperator(self.dirichlet_tag) * u
286 dir_v = BoundarizeOperator(self.dirichlet_tag) * v
287
288 dir_bc = join_fields(dir_c, -dir_u, dir_v)
289
290
291 neu_c = BoundarizeOperator(self.neumann_tag) * c
292 neu_u = BoundarizeOperator(self.neumann_tag) * u
293 neu_v = BoundarizeOperator(self.neumann_tag) * v
294
295 neu_bc = join_fields(neu_c, neu_u, -neu_v)
296
297
298 from hedge.optemplate import make_normal
299 rad_normal = make_normal(self.radiation_tag, d)
300
301 rad_c = BoundarizeOperator(self.radiation_tag) * c
302 rad_u = BoundarizeOperator(self.radiation_tag) * u
303 rad_v = BoundarizeOperator(self.radiation_tag) * v
304
305 rad_bc = join_fields(
306 rad_c,
307 0.5*(rad_u - self.time_sign*numpy.dot(rad_normal, rad_v)),
308 0.5*rad_normal*(numpy.dot(rad_normal, rad_v) - self.time_sign*rad_u)
309 )
310
311
312 nabla = make_nabla(d)
313 flux_op = get_flux_operator(self.flux())
314
315 return (
316 - join_fields(
317 -numpy.dot(nabla, self.time_sign*c*v),
318 -(nabla*(self.time_sign*c*u))
319 )
320 +
321 InverseMassOperator() * (
322 flux_op*flux_w
323 + flux_op * pair_with_boundary(flux_w, dir_bc, self.dirichlet_tag)
324 + flux_op * pair_with_boundary(flux_w, neu_bc, self.neumann_tag)
325 + flux_op * pair_with_boundary(flux_w, rad_bc, self.radiation_tag)
326 ))
327
328
329 - def bind(self, discr):
330 from hedge.mesh import check_bc_coverage
331 check_bc_coverage(discr.mesh, [
332 self.dirichlet_tag,
333 self.neumann_tag,
334 self.radiation_tag])
335
336 compiled_op_template = discr.compile(self.op_template())
337
338 def rhs(t, w):
339 rhs = compiled_op_template(w=w,
340 c=self.c.volume_interpolant(t, discr))
341
342 if self.source is not None:
343 rhs[0] += self.source.volume_interpolant(t, discr)
344
345 return rhs
346
347 return rhs
348
349
350
351
352
353
354
356 """An nD Euler operator.
357
358 Field order is [rho E rho_u_x rho_u_y ...].
359 """
360 - def __init__(self, dimensions, gamma, bc):
364
367
370
373
375 from hedge.tools import make_obj_array
376 return make_obj_array([
377 rho_u_i/self.rho(q)
378 for rho_u_i in self.rho_u(q)])
379
381 from hedge.optemplate import make_vector_field, \
382 make_common_subexpression as cse
383
384 def u(q):
385 return cse(self.u(q))
386
387 def p(q):
388 return cse((self.gamma-1)*(self.e(q) - 0.5*numpy.dot(self.rho_u(q), u(q))))
389
390 def flux(q):
391 from pytools import delta
392 from hedge.tools import make_obj_array, join_fields
393 return [
394 cse(join_fields(
395
396 self.rho_u(q)[i],
397
398
399 cse(self.e(q)+p(q))*u(q)[i],
400
401
402 make_obj_array([
403 self.rho_u(q)[i]*self.u(q)[j] + delta(i,j) * p(q)
404 for j in range(self.dimensions)
405 ])
406 ))
407 for i in range(self.dimensions)]
408
409 from hedge.optemplate import make_nabla, InverseMassOperator, \
410 ElementwiseMaxOperator
411
412 from pymbolic import var
413 sqrt = var("sqrt")
414
415 state = make_vector_field("q", self.dimensions+2)
416 bc_state = make_vector_field("bc_q", self.dimensions+2)
417
418 c = cse(sqrt(self.gamma*p(state)/self.rho(state)))
419
420 speed = sqrt(numpy.dot(u(state), u(state))) + c
421
422 from hedge.tools import make_lax_friedrichs_flux, join_fields
423 from hedge.mesh import TAG_ALL
424 return join_fields(
425 (- numpy.dot(make_nabla(self.dimensions), flux(state))
426 + InverseMassOperator()*make_lax_friedrichs_flux(
427 wave_speed=ElementwiseMaxOperator()*c,
428 state=state, flux_func=flux,
429 bdry_tags_and_states=[
430 (TAG_ALL, bc_state)
431 ],
432 strong=True
433 )),
434 speed)
435
436 - def bind(self, discr):
447
448 return wrap
449