diff --git a/.gitignore b/.gitignore
index 05e0c40e71bd1f2e918495e6e811370baf1b687b..e6efa6fae37f239c8ed880ac0cf08db633158bca 100644
--- a/.gitignore
+++ b/.gitignore
@@ -20,3 +20,12 @@ examples/*.pdf
*.vtu
*.vts
+
+run-debug-*
+
+*.vtu
+*.pvtu
+*.pvd
+*.dot
+*.vtk
+*.silo
diff --git a/examples/advection/advection.py b/examples/advection/advection.py
new file mode 100644
index 0000000000000000000000000000000000000000..e912531c3179dd67e7d886391edf3bb91ce17c7d
--- /dev/null
+++ b/examples/advection/advection.py
@@ -0,0 +1,176 @@
+# Hedge - the Hybrid'n'Easy DG Environment
+# Copyright (C) 2007 Andreas Kloeckner
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+
+from __future__ import division
+import numpy
+import numpy.linalg as la
+
+
+
+
+def main(write_output=True, flux_type_arg="upwind"):
+ from hedge.tools import mem_checkpoint
+ from math import sin, cos, pi, sqrt
+ from math import floor
+
+ from hedge.backends import guess_run_context
+ rcon = guess_run_context()
+
+ def f(x):
+ return sin(pi*x)
+
+ def u_analytic(x, el, t):
+ return f((-numpy.dot(v, x)/norm_v+t*norm_v))
+
+ def boundary_tagger(vertices, el, face_nr, all_v):
+ if numpy.dot(el.face_normals[face_nr], v) < 0:
+ return ["inflow"]
+ else:
+ return ["outflow"]
+
+ dim = 2
+
+ if dim == 1:
+ v = numpy.array([1])
+ if rcon.is_head_rank:
+ from hedge.mesh.generator import make_uniform_1d_mesh
+ mesh = make_uniform_1d_mesh(0, 2, 10, periodic=True)
+ elif dim == 2:
+ v = numpy.array([2,0])
+ if rcon.is_head_rank:
+ from hedge.mesh.generator import make_disk_mesh
+ mesh = make_disk_mesh(boundary_tagger=boundary_tagger)
+ elif dim == 3:
+ v = numpy.array([0,0,1])
+ if rcon.is_head_rank:
+ from hedge.mesh.generator import make_cylinder_mesh, make_ball_mesh, make_box_mesh
+
+ mesh = make_cylinder_mesh(max_volume=0.04, height=2, boundary_tagger=boundary_tagger,
+ periodic=False, radial_subdivisions=32)
+ else:
+ raise RuntimeError, "bad number of dimensions"
+
+ norm_v = la.norm(v)
+
+ if rcon.is_head_rank:
+ mesh_data = rcon.distribute_mesh(mesh)
+ else:
+ mesh_data = rcon.receive_mesh()
+
+ if dim != 1:
+ mesh_data = mesh_data.reordered_by("cuthill")
+
+ discr = rcon.make_discretization(mesh_data, order=4)
+ vis_discr = discr
+
+ from hedge.visualization import VtkVisualizer
+ if write_output:
+ vis = VtkVisualizer(vis_discr, rcon, "fld")
+
+ # operator setup ----------------------------------------------------------
+ from hedge.data import \
+ ConstantGivenFunction, \
+ TimeConstantGivenFunction, \
+ TimeDependentGivenFunction
+ from hedge.models.advection import StrongAdvectionOperator, WeakAdvectionOperator
+ op = WeakAdvectionOperator(v,
+ inflow_u=TimeDependentGivenFunction(u_analytic),
+ flux_type=flux_type_arg)
+
+ u = discr.interpolate_volume_function(lambda x, el: u_analytic(x, el, 0))
+
+ # timestep setup ----------------------------------------------------------
+ from hedge.timestep.runge_kutta import LSRK4TimeStepper
+ stepper = LSRK4TimeStepper()
+
+ if rcon.is_head_rank:
+ print "%d elements" % len(discr.mesh.elements)
+
+ # diagnostics setup -------------------------------------------------------
+ from pytools.log import LogManager, \
+ add_general_quantities, \
+ add_simulation_quantities, \
+ add_run_info
+
+ if write_output:
+ log_file_name = "advection.dat"
+ else:
+ log_file_name = None
+
+ logmgr = LogManager(log_file_name, "w", rcon.communicator)
+ add_run_info(logmgr)
+ add_general_quantities(logmgr)
+ add_simulation_quantities(logmgr)
+ discr.add_instrumentation(logmgr)
+
+ stepper.add_instrumentation(logmgr)
+
+ from hedge.log import Integral, LpNorm
+ u_getter = lambda: u
+ logmgr.add_quantity(Integral(u_getter, discr, name="int_u"))
+ logmgr.add_quantity(LpNorm(u_getter, discr, p=1, name="l1_u"))
+ logmgr.add_quantity(LpNorm(u_getter, discr, name="l2_u"))
+
+ logmgr.add_watches(["step.max", "t_sim.max", "l2_u", "t_step.max"])
+
+ # timestep loop -----------------------------------------------------------
+ rhs = op.bind(discr)
+
+ try:
+ from hedge.timestep import times_and_steps
+ step_it = times_and_steps(
+ final_time=3, logmgr=logmgr,
+ max_dt_getter=lambda t: op.estimate_timestep(discr,
+ stepper=stepper, t=t, fields=u))
+
+ for step, t, dt in step_it:
+ if step % 5 == 0 and write_output:
+ visf = vis.make_file("fld-%04d" % step)
+ vis.add_data(visf, [
+ ("u", discr.convert_volume(u, kind="numpy")),
+ ], time=t, step=step)
+ visf.close()
+
+ u = stepper(u, t, dt, rhs)
+
+ true_u = discr.interpolate_volume_function(lambda x, el: u_analytic(x, el, t))
+ print discr.norm(u-true_u)
+ assert discr.norm(u-true_u) < 1e-2
+ finally:
+ if write_output:
+ vis.close()
+
+ logmgr.close()
+ discr.close()
+
+
+
+
+if __name__ == "__main__":
+ main()
+
+
+
+
+# entry points for py.test ----------------------------------------------------
+def test_advection():
+ from pytools.test import mark_test
+ mark_long = mark_test.long
+
+ for flux_type in ["upwind", "central", "lf"]:
+ yield "advection with %s flux" % flux_type, \
+ mark_long(main), False, flux_type
diff --git a/examples/advection/space-dep.dat b/examples/advection/space-dep.dat
new file mode 100644
index 0000000000000000000000000000000000000000..78e1f83c1721d1491d9eb5fce605c90b5607b872
Binary files /dev/null and b/examples/advection/space-dep.dat differ
diff --git a/examples/advection/var-velocity.py b/examples/advection/var-velocity.py
new file mode 100644
index 0000000000000000000000000000000000000000..81fb7e675525ed223320f0aea6eb9a5d6e85ba39
--- /dev/null
+++ b/examples/advection/var-velocity.py
@@ -0,0 +1,258 @@
+# Hedge - the Hybrid'n'Easy DG Environment
+# Copyright (C) 2009 Andreas Stock
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+
+
+
+from __future__ import division
+import numpy
+
+
+
+def main(write_output=True, flux_type_arg="central", use_quadrature=True,
+ final_time=20):
+ from math import sin, cos, pi, sqrt
+
+ from hedge.backends import guess_run_context
+ rcon = guess_run_context()
+
+ # mesh setup --------------------------------------------------------------
+ if rcon.is_head_rank:
+ #from hedge.mesh.generator import make_disk_mesh
+ #mesh = make_disk_mesh()
+ from hedge.mesh.generator import make_rect_mesh
+ mesh = make_rect_mesh(a=(-1,-1),b=(1,1),max_area=0.008)
+
+ if rcon.is_head_rank:
+ mesh_data = rcon.distribute_mesh(mesh)
+ else:
+ mesh_data = rcon.receive_mesh()
+
+ # space-time-dependent-velocity-field -------------------------------------
+ # simple vortex
+ class TimeDependentVField:
+ """ `TimeDependentVField` is a callable expecting `(x, t)` representing space and time
+
+ `x` is of the length of the spatial dimension and `t` is the time."""
+ shape = (2,)
+
+ def __call__(self, pt, el, t):
+ x, y = pt
+ # Correction-Factor to make the speed zero on the on the boundary
+ #fac = (1-x**2)*(1-y**2)
+ fac = 1.
+ return numpy.array([-y*fac, x*fac]) * cos(pi*t)
+
+ class VField:
+ """ `VField` is a callable expecting `(x)` representing space
+
+ `x` is of the length of the spatial dimension."""
+ shape = (2,)
+
+ def __call__(self, pt, el):
+ x, y = pt
+ # Correction-Factor to make the speed zero on the on the boundary
+ #fac = (1-x**2)*(1-y**2)
+ fac = 1.
+ return numpy.array([-y*fac, x*fac])
+
+ # space-time-dependent State BC (optional)-----------------------------------
+ class TimeDependentBc_u:
+ """ space and time dependent BC for state u"""
+ def __call__(self, pt, el, t):
+ x, y = pt
+ if t <= 0.5:
+ if x > 0:
+ return 1
+ else:
+ return 0
+ else:
+ return 0
+
+ class Bc_u:
+ """ Only space dependent BC for state u"""
+ def __call__(seld, pt, el):
+ x, y = pt
+ if x > 0:
+ return 1
+ else:
+ return 0
+
+
+ # operator setup ----------------------------------------------------------
+ # In the operator setup it is possible to switch between a only space
+ # dependent velocity field `VField` or a time and space dependent
+ # `TimeDependentVField`.
+ # For `TimeDependentVField`: advec_v=TimeDependentGivenFunction(VField())
+ # For `VField`: advec_v=TimeConstantGivenFunction(GivenFunction(VField()))
+ # Same for the Bc_u Function! If you don't define Bc_u then the BC for u = 0.
+
+ from hedge.data import \
+ ConstantGivenFunction, \
+ TimeConstantGivenFunction, \
+ TimeDependentGivenFunction, \
+ GivenFunction
+ from hedge.models.advection import VariableCoefficientAdvectionOperator
+ op = VariableCoefficientAdvectionOperator(mesh.dimensions,
+ #advec_v=TimeDependentGivenFunction(
+ # TimeDependentVField()),
+ advec_v=TimeConstantGivenFunction(
+ GivenFunction(VField())),
+ #bc_u_f=TimeDependentGivenFunction(
+ # TimeDependentBc_u()),
+ bc_u_f=TimeConstantGivenFunction(
+ GivenFunction(Bc_u())),
+ flux_type=flux_type_arg)
+
+ # discretization setup ----------------------------------------------------
+ order = 5
+ if use_quadrature:
+ quad_min_degrees = {"quad": 3*order}
+ else:
+ quad_min_degrees = {}
+
+ discr = rcon.make_discretization(mesh_data, order=order,
+ default_scalar_type=numpy.float64,
+ debug=["cuda_no_plan"],
+ quad_min_degrees=quad_min_degrees,
+ tune_for=op.op_template(),
+
+ )
+ vis_discr = discr
+
+ # visualization setup -----------------------------------------------------
+ from hedge.visualization import VtkVisualizer
+ if write_output:
+ vis = VtkVisualizer(vis_discr, rcon, "fld")
+
+ # initial condition -------------------------------------------------------
+ if True:
+ def initial(pt, el):
+ # Gauss pulse
+ from math import exp
+ x = (pt-numpy.array([0.3, 0.5]))*8
+ return exp(-numpy.dot(x, x))
+ else:
+ def initial(pt, el):
+ # Rectangle
+ x, y = pt
+ if abs(x) < 0.5 and abs(y) < 0.2:
+ return 2
+ else:
+ return 1
+
+ u = discr.interpolate_volume_function(initial)
+
+ # timestep setup ----------------------------------------------------------
+ from hedge.timestep.runge_kutta import LSRK4TimeStepper
+ stepper = LSRK4TimeStepper(
+ vector_primitive_factory=discr.get_vector_primitive_factory())
+
+ if rcon.is_head_rank:
+ print "%d elements" % len(discr.mesh.elements)
+
+ # filter setup-------------------------------------------------------------
+ from hedge.discretization import ExponentialFilterResponseFunction
+ from hedge.optemplate.operators import FilterOperator
+ mode_filter = FilterOperator(
+ ExponentialFilterResponseFunction(min_amplification=0.9,order=4))\
+ .bind(discr)
+
+ # diagnostics setup -------------------------------------------------------
+ from pytools.log import LogManager, \
+ add_general_quantities, \
+ add_simulation_quantities, \
+ add_run_info
+
+ if write_output:
+ log_file_name = "space-dep.dat"
+ else:
+ log_file_name = None
+
+ logmgr = LogManager(log_file_name, "w", rcon.communicator)
+ add_run_info(logmgr)
+ add_general_quantities(logmgr)
+ add_simulation_quantities(logmgr)
+ discr.add_instrumentation(logmgr)
+
+ stepper.add_instrumentation(logmgr)
+
+ from hedge.log import Integral, LpNorm
+ u_getter = lambda: u
+ logmgr.add_quantity(Integral(u_getter, discr, name="int_u"))
+ logmgr.add_quantity(LpNorm(u_getter, discr, p=1, name="l1_u"))
+ logmgr.add_quantity(LpNorm(u_getter, discr, name="l2_u"))
+
+ logmgr.add_watches(["step.max", "t_sim.max", "l2_u", "t_step.max"])
+
+ # Initialize v for data output:
+ v = op.advec_v.volume_interpolant(0, discr)
+
+ # timestep loop -----------------------------------------------------------
+ rhs = op.bind(discr)
+ try:
+ from hedge.timestep import times_and_steps
+ step_it = times_and_steps(
+ final_time=final_time, logmgr=logmgr,
+ max_dt_getter=lambda t: op.estimate_timestep(discr,
+ stepper=stepper, t=t, fields=u))
+
+ for step, t, dt in step_it:
+ if step % 10 == 0 and write_output:
+ visf = vis.make_file("fld-%04d" % step)
+ vis.add_data(visf, [
+ ("u", discr.convert_volume(u, kind="numpy")),
+ ("v", discr.convert_volume(v, kind="numpy"))
+ ], time=t, step=step)
+ visf.close()
+
+ u = stepper(u, t, dt, rhs)
+
+ # We're feeding in a discontinuity through the BCs.
+ # Quadrature does not help with shock capturing--
+ # therefore we do need to filter here, regardless
+ # of whether quadrature is enabled.
+ u = mode_filter(u)
+
+ assert discr.norm(u) < 10
+
+ finally:
+ if write_output:
+ vis.close()
+
+ logmgr.close()
+ discr.close()
+
+
+
+if __name__ == "__main__":
+ main()
+
+
+
+
+# entry points for py.test ----------------------------------------------------
+def test_var_velocity_advection():
+ from pytools.test import mark_test
+ mark_long = mark_test.long
+
+ for flux_type in ["upwind", "central", "lf"]:
+ for use_quadrature in [False, True]:
+ descr = "variable-velocity-advection with %s flux" % flux_type
+ if use_quadrature:
+ descr += " and quadrature"
+
+ yield descr, mark_long(main), False, flux_type, use_quadrature, 1
diff --git a/examples/burgers/burgers.dat b/examples/burgers/burgers.dat
new file mode 100644
index 0000000000000000000000000000000000000000..baf59af8ed316993b4c2f5eaedea2b2c2538f17d
Binary files /dev/null and b/examples/burgers/burgers.dat differ
diff --git a/examples/burgers/burgers.py b/examples/burgers/burgers.py
new file mode 100644
index 0000000000000000000000000000000000000000..20b4832a2b9bae479ff4d95c6da6fbc40b411352
--- /dev/null
+++ b/examples/burgers/burgers.py
@@ -0,0 +1,238 @@
+# Hedge - the Hybrid'n'Easy DG Environment
+# Copyright (C) 2007 Andreas Kloeckner
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+
+from __future__ import division
+import numpy
+import numpy.linalg as la
+from math import sin, cos, pi, sqrt
+from pytools.test import mark_test
+
+
+
+
+class ExactTestCase:
+ a = 0
+ b = 150
+ final_time = 1000
+
+ def u0(self, x):
+ return self.u_exact(x, 0)
+
+ def u_exact(self, x, t):
+ # CAUTION: This gets the shock speed wrong as soon as the pulse
+ # starts interacting with itself.
+
+ def f(x, shock_loc):
+ if x < (t-40)/4:
+ return 1/4
+ else:
+ if t < 40:
+ if x < (3*t)/4:
+ return (x+15)/(t+20)
+ elif x < (t+80)/4:
+ return (x-30)/(t-40)
+ else:
+ return 1/4
+ else:
+ if x < shock_loc:
+ return (x+15)/(t+20)
+ else:
+ return 1/4
+
+ from math import sqrt
+
+ shock_loc = 30*sqrt(2*t+40)/sqrt(120) + t/4 - 10
+ shock_win = (shock_loc + 20) // self.b
+ x += shock_win * 150
+
+ x -= 20
+
+ return max(f(x, shock_loc), f(x-self.b, shock_loc-self.b))
+
+class OffCenterMigratingTestCase:
+ a = -pi
+ b = pi
+ final_time = 10
+
+ def u0(self, x):
+ return -0.4+sin(x+0.1)
+
+
+class CenteredStationaryTestCase:
+ # does funny things to P-P
+ a = -pi
+ b = pi
+ final_time = 10
+
+ def u0(self, x):
+ return -sin(x)
+
+class OffCenterStationaryTestCase:
+ # does funny things to P-P
+ a = -pi
+ b = pi
+ final_time = 10
+
+ def u0(self, x):
+ return -sin(x+0.3)
+
+
+
+def main(write_output=True, flux_type_arg="upwind",
+ #case = CenteredStationaryTestCase(),
+ #case = OffCenterStationaryTestCase(),
+ #case = OffCenterMigratingTestCase(),
+ case = ExactTestCase(),
+ ):
+ from hedge.backends import guess_run_context
+ rcon = guess_run_context()
+
+ order = 3
+ if rcon.is_head_rank:
+ if True:
+ from hedge.mesh.generator import make_uniform_1d_mesh
+ mesh = make_uniform_1d_mesh(case.a, case.b, 20, periodic=True)
+ else:
+ from hedge.mesh.generator import make_rect_mesh
+ print (pi*2)/(11*5*2)
+ mesh = make_rect_mesh((-pi, -1), (pi, 1),
+ periodicity=(True, True),
+ subdivisions=(11,5),
+ max_area=(pi*2)/(11*5*2)
+ )
+
+ if rcon.is_head_rank:
+ mesh_data = rcon.distribute_mesh(mesh)
+ else:
+ mesh_data = rcon.receive_mesh()
+
+ discr = rcon.make_discretization(mesh_data, order=order,
+ quad_min_degrees={"quad": 3*order})
+
+ if write_output:
+ from hedge.visualization import VtkVisualizer
+ vis = VtkVisualizer(discr, rcon, "fld")
+
+ # operator setup ----------------------------------------------------------
+ from hedge.second_order import IPDGSecondDerivative
+
+ from hedge.models.burgers import BurgersOperator
+ op = BurgersOperator(mesh.dimensions,
+ viscosity_scheme=IPDGSecondDerivative())
+
+ if rcon.is_head_rank:
+ print "%d elements" % len(discr.mesh.elements)
+
+ # exact solution ----------------------------------------------------------
+ import pymbolic
+ var = pymbolic.var
+
+ u = discr.interpolate_volume_function(lambda x, el: case.u0(x[0]))
+
+ # diagnostics setup -------------------------------------------------------
+ from pytools.log import LogManager, \
+ add_general_quantities, \
+ add_simulation_quantities, \
+ add_run_info
+
+ if write_output:
+ log_file_name = "burgers.dat"
+ else:
+ log_file_name = None
+
+ logmgr = LogManager(log_file_name, "w", rcon.communicator)
+ add_run_info(logmgr)
+ add_general_quantities(logmgr)
+ add_simulation_quantities(logmgr)
+ discr.add_instrumentation(logmgr)
+
+ from hedge.log import LpNorm
+ u_getter = lambda: u
+ logmgr.add_quantity(LpNorm(u_getter, discr, p=1, name="l1_u"))
+
+ logmgr.add_watches(["step.max", "t_sim.max", "l1_u", "t_step.max"])
+
+ # timestep loop -----------------------------------------------------------
+ rhs = op.bind(discr)
+
+ from hedge.timestep.runge_kutta import ODE45TimeStepper, LSRK4TimeStepper
+ stepper = ODE45TimeStepper()
+
+ stepper.add_instrumentation(logmgr)
+
+ try:
+ from hedge.timestep import times_and_steps
+ # for visc=0.01
+ #stab_fac = 0.1 # RK4
+ #stab_fac = 1.6 # dumka3(3), central
+ #stab_fac = 3 # dumka3(4), central
+
+ #stab_fac = 0.01 # RK4
+ stab_fac = 0.2 # dumka3(3), central
+ #stab_fac = 3 # dumka3(4), central
+
+ dt = stab_fac*op.estimate_timestep(discr,
+ stepper=LSRK4TimeStepper(), t=0, fields=u)
+
+ step_it = times_and_steps(
+ final_time=case.final_time, logmgr=logmgr, max_dt_getter=lambda t: dt)
+ from hedge.optemplate import InverseVandermondeOperator
+ inv_vdm = InverseVandermondeOperator().bind(discr)
+
+ for step, t, dt in step_it:
+ if step % 3 == 0 and write_output:
+ if hasattr(case, "u_exact"):
+ extra_fields = [
+ ("u_exact",
+ discr.interpolate_volume_function(
+ lambda x, el: case.u_exact(x[0], t)))]
+ else:
+ extra_fields = []
+
+ visf = vis.make_file("fld-%04d" % step)
+ vis.add_data(visf, [
+ ("u", u),
+ ] + extra_fields,
+ time=t,
+ step=step)
+ visf.close()
+
+ u = stepper(u, t, dt, rhs)
+
+ if isinstance(case, ExactTestCase):
+ assert discr.norm(u, 1) < 50
+
+ finally:
+ if write_output:
+ vis.close()
+
+ logmgr.save()
+
+
+
+
+if __name__ == "__main__":
+ main()
+
+
+
+
+# entry points for py.test ----------------------------------------------------
+@mark_test.long
+def test_stability():
+ main(write_output=False)
+
diff --git a/examples/conftest.py b/examples/conftest.py
new file mode 100644
index 0000000000000000000000000000000000000000..ec99a4c7fd882c79b4c0e1b6b78b16ab578b8532
--- /dev/null
+++ b/examples/conftest.py
@@ -0,0 +1,7 @@
+# This file tells py.test to scan for test_xxx() functions in
+# any file below here, not just those named test_xxxx.py.
+
+
+def pytest_collect_file(path, parent):
+ if "hedge/examples" in str(path.dirpath()) and path.ext == ".py":
+ return parent.Module(path, parent=parent)
diff --git a/examples/gas_dynamics/box-in-box.py b/examples/gas_dynamics/box-in-box.py
new file mode 100644
index 0000000000000000000000000000000000000000..ac3be82f7d5c230a6150243354fc359938fe4f24
--- /dev/null
+++ b/examples/gas_dynamics/box-in-box.py
@@ -0,0 +1,235 @@
+# Hedge - the Hybrid'n'Easy DG Environment
+# Copyright (C) 2008 Andreas Kloeckner
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+
+from __future__ import division
+import numpy
+
+
+def make_boxmesh():
+ from meshpy.tet import MeshInfo, build
+ from meshpy.geometry import GeometryBuilder, Marker, make_box
+
+ geob = GeometryBuilder()
+
+ box_marker = Marker.FIRST_USER_MARKER
+ extent_small = 0.1*numpy.ones(3, dtype=numpy.float64)
+
+ geob.add_geometry(*make_box(-extent_small, extent_small))
+
+ # make small "separator box" for region attribute
+
+ geob.add_geometry(
+ *make_box(
+ -extent_small*4,
+ numpy.array([4, 0.4, 0.4], dtype=numpy.float64)))
+
+ geob.add_geometry(
+ *make_box(
+ numpy.array([-1, -1, -1], dtype=numpy.float64),
+ numpy.array([5, 1, 1], dtype=numpy.float64)))
+
+ mesh_info = MeshInfo()
+ geob.set(mesh_info)
+ mesh_info.set_holes([(0, 0, 0)])
+
+ # region attributes
+ mesh_info.regions.resize(1)
+ mesh_info.regions[0] = (
+ # point in region
+ list(extent_small*2) + [
+ # region number
+ 1,
+ # max volume in region
+ #0.0001
+ 0.005
+ ])
+
+ mesh = build(mesh_info, max_volume=0.02,
+ volume_constraints=True, attributes=True)
+ print "%d elements" % len(mesh.elements)
+ #mesh.write_vtk("box-in-box.vtk")
+ #print "done writing"
+
+ fvi2fm = mesh.face_vertex_indices_to_face_marker
+
+ face_marker_to_tag = {
+ box_marker: "noslip",
+ Marker.MINUS_X: "inflow",
+ Marker.PLUS_X: "outflow",
+ Marker.MINUS_Y: "inflow",
+ Marker.PLUS_Y: "inflow",
+ Marker.PLUS_Z: "inflow",
+ Marker.MINUS_Z: "inflow"
+ }
+
+ def bdry_tagger(fvi, el, fn, all_v):
+ face_marker = fvi2fm[fvi]
+ return [face_marker_to_tag[face_marker]]
+
+ from hedge.mesh import make_conformal_mesh
+ return make_conformal_mesh(
+ mesh.points, mesh.elements, bdry_tagger)
+
+
+def main():
+ from hedge.backends import guess_run_context
+ rcon = guess_run_context(["cuda"])
+
+ if rcon.is_head_rank:
+ mesh = make_boxmesh()
+ #from hedge.mesh import make_rect_mesh
+ #mesh = make_rect_mesh(
+ # boundary_tagger=lambda fvi, el, fn, all_v: ["inflow"])
+ mesh_data = rcon.distribute_mesh(mesh)
+ else:
+ mesh_data = rcon.receive_mesh()
+
+ for order in [3]:
+ from pytools import add_python_path_relative_to_script
+ add_python_path_relative_to_script("..")
+
+ from gas_dynamics_initials import UniformMachFlow
+ box = UniformMachFlow(angle_of_attack=0)
+
+ from hedge.models.gas_dynamics import GasDynamicsOperator
+ op = GasDynamicsOperator(dimensions=3,
+ gamma=box.gamma, mu=box.mu,
+ prandtl=box.prandtl, spec_gas_const=box.spec_gas_const,
+ bc_inflow=box, bc_outflow=box, bc_noslip=box,
+ inflow_tag="inflow", outflow_tag="outflow", noslip_tag="noslip")
+
+ discr = rcon.make_discretization(mesh_data, order=order,
+ debug=[
+ #"cuda_no_plan",
+ #"cuda_dump_kernels",
+ #"dump_dataflow_graph",
+ #"dump_optemplate_stages",
+ #"dump_dataflow_graph",
+ #"print_op_code",
+ "cuda_no_plan_el_local",
+ ],
+ default_scalar_type=numpy.float32,
+ tune_for=op.op_template())
+
+ from hedge.visualization import SiloVisualizer, VtkVisualizer # noqa
+ #vis = VtkVisualizer(discr, rcon, "shearflow-%d" % order)
+ vis = SiloVisualizer(discr, rcon)
+
+ fields = box.volume_interpolant(0, discr)
+
+ navierstokes_ex = op.bind(discr)
+
+ max_eigval = [0]
+
+ def rhs(t, q):
+ ode_rhs, speed = navierstokes_ex(t, q)
+ max_eigval[0] = speed
+ return ode_rhs
+
+ rhs(0, fields)
+
+ if rcon.is_head_rank:
+ print "---------------------------------------------"
+ print "order %d" % order
+ print "---------------------------------------------"
+ print "#elements=", len(mesh.elements)
+
+ from hedge.timestep import RK4TimeStepper
+ stepper = RK4TimeStepper()
+
+ # diagnostics setup ---------------------------------------------------
+ from pytools.log import LogManager, add_general_quantities, \
+ add_simulation_quantities, add_run_info
+
+ logmgr = LogManager("navierstokes-%d.dat" % order, "w", rcon.communicator)
+ add_run_info(logmgr)
+ add_general_quantities(logmgr)
+ add_simulation_quantities(logmgr)
+ discr.add_instrumentation(logmgr)
+ stepper.add_instrumentation(logmgr)
+
+ logmgr.add_watches(["step.max", "t_sim.max", "t_step.max"])
+
+ from pytools.log import LogQuantity
+
+ class ChangeSinceLastStep(LogQuantity):
+ """Records the change of a variable between a time step and the previous
+ one"""
+
+ def __init__(self, name="change"):
+ LogQuantity.__init__(self, name, "1", "Change since last time step")
+
+ self.old_fields = 0
+
+ def __call__(self):
+ result = discr.norm(fields - self.old_fields)
+ self.old_fields = fields
+ return result
+
+ logmgr.add_quantity(ChangeSinceLastStep())
+
+ # timestep loop -------------------------------------------------------
+ try:
+ from hedge.timestep import times_and_steps
+ step_it = times_and_steps(
+ final_time=200,
+ #max_steps=500,
+ logmgr=logmgr,
+ max_dt_getter=lambda t: op.estimate_timestep(discr,
+ stepper=stepper, t=t, max_eigenvalue=max_eigval[0]))
+
+ for step, t, dt in step_it:
+ if step % 200 == 0:
+ #if False:
+ visf = vis.make_file("box-%d-%06d" % (order, step))
+
+ #rhs_fields = rhs(t, fields)
+
+ vis.add_data(visf,
+ [
+ ("rho", discr.convert_volume(
+ op.rho(fields), kind="numpy")),
+ ("e", discr.convert_volume(
+ op.e(fields), kind="numpy")),
+ ("rho_u", discr.convert_volume(
+ op.rho_u(fields), kind="numpy")),
+ ("u", discr.convert_volume(
+ op.u(fields), kind="numpy")),
+
+ # ("rhs_rho", discr.convert_volume(
+ # op.rho(rhs_fields), kind="numpy")),
+ # ("rhs_e", discr.convert_volume(
+ # op.e(rhs_fields), kind="numpy")),
+ # ("rhs_rho_u", discr.convert_volume(
+ # op.rho_u(rhs_fields), kind="numpy")),
+ ],
+ expressions=[
+ ("p", "(0.4)*(e- 0.5*(rho_u*u))"),
+ ],
+ time=t, step=step
+ )
+ visf.close()
+
+ fields = stepper(fields, t, dt, rhs)
+
+ finally:
+ vis.close()
+ logmgr.save()
+ discr.close()
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/gas_dynamics/euler/sine-wave.py b/examples/gas_dynamics/euler/sine-wave.py
new file mode 100644
index 0000000000000000000000000000000000000000..9f751a86eb4954c19a05c6b8a3fed31257db57fd
--- /dev/null
+++ b/examples/gas_dynamics/euler/sine-wave.py
@@ -0,0 +1,198 @@
+# Hedge - the Hybrid'n'Easy DG Environment
+# Copyright (C) 2008 Andreas Kloeckner
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+
+
+
+from __future__ import division
+import numpy
+import numpy.linalg as la
+
+
+
+
+class SineWave:
+ def __init__(self):
+ self.gamma = 1.4
+ self.mu = 0
+ self.prandtl = 0.72
+ self.spec_gas_const = 287.1
+
+ def __call__(self, t, x_vec):
+ rho = 2 + numpy.sin(x_vec[0] + x_vec[1] + x_vec[2] - 2 * t)
+ velocity = numpy.array([1, 1, 0])
+ p = 1
+ e = p/(self.gamma-1) + rho/2 * numpy.dot(velocity, velocity)
+ rho_u = rho * velocity[0]
+ rho_v = rho * velocity[1]
+ rho_w = rho * velocity[2]
+
+ from hedge.tools import join_fields
+ return join_fields(rho, e, rho_u, rho_v, rho_w)
+
+ def properties(self):
+ return(self.gamma, self.mu, self.prandtl, self.spec_gas_const)
+
+ def volume_interpolant(self, t, discr):
+ return discr.convert_volume(
+ self(t, discr.nodes.T),
+ kind=discr.compute_kind)
+
+ def boundary_interpolant(self, t, discr, tag):
+ return discr.convert_boundary(
+ self(t, discr.get_boundary(tag).nodes.T),
+ tag=tag, kind=discr.compute_kind)
+
+
+
+
+def main(final_time=1, write_output=False):
+ from hedge.backends import guess_run_context
+ rcon = guess_run_context()
+
+ from hedge.tools import EOCRecorder, to_obj_array
+ eoc_rec = EOCRecorder()
+
+ if rcon.is_head_rank:
+ from hedge.mesh import make_box_mesh
+ mesh = make_box_mesh((0,0,0), (10,10,10), max_volume=0.5)
+ mesh_data = rcon.distribute_mesh(mesh)
+ else:
+ mesh_data = rcon.receive_mesh()
+
+ for order in [3, 4, 5]:
+ discr = rcon.make_discretization(mesh_data, order=order,
+ default_scalar_type=numpy.float64)
+
+ from hedge.visualization import SiloVisualizer, VtkVisualizer
+ vis = VtkVisualizer(discr, rcon, "sinewave-%d" % order)
+ #vis = SiloVisualizer(discr, rcon)
+
+ sinewave = SineWave()
+ fields = sinewave.volume_interpolant(0, discr)
+ gamma, mu, prandtl, spec_gas_const = sinewave.properties()
+
+ from hedge.mesh import TAG_ALL
+ from hedge.models.gas_dynamics import GasDynamicsOperator
+ op = GasDynamicsOperator(dimensions=mesh.dimensions, gamma=gamma, mu=mu,
+ prandtl=prandtl, spec_gas_const=spec_gas_const,
+ bc_inflow=sinewave, bc_outflow=sinewave, bc_noslip=sinewave,
+ inflow_tag=TAG_ALL, source=None)
+
+ euler_ex = op.bind(discr)
+
+ max_eigval = [0]
+ def rhs(t, q):
+ ode_rhs, speed = euler_ex(t, q)
+ max_eigval[0] = speed
+ return ode_rhs
+ rhs(0, fields)
+
+ if rcon.is_head_rank:
+ print "---------------------------------------------"
+ print "order %d" % order
+ print "---------------------------------------------"
+ print "#elements=", len(mesh.elements)
+
+ from hedge.timestep import RK4TimeStepper
+ stepper = RK4TimeStepper()
+
+ # diagnostics setup ---------------------------------------------------
+ from pytools.log import LogManager, add_general_quantities, \
+ add_simulation_quantities, add_run_info
+
+ if write_output:
+ log_name = ("euler-sinewave-%(order)d-%(els)d.dat"
+ % {"order":order, "els":len(mesh.elements)})
+ else:
+ log_name = False
+ logmgr = LogManager(log_name, "w", rcon.communicator)
+ add_run_info(logmgr)
+ add_general_quantities(logmgr)
+ add_simulation_quantities(logmgr)
+ discr.add_instrumentation(logmgr)
+ stepper.add_instrumentation(logmgr)
+
+ logmgr.add_watches(["step.max", "t_sim.max", "t_step.max"])
+
+ # timestep loop -------------------------------------------------------
+ try:
+ from hedge.timestep import times_and_steps
+ step_it = times_and_steps(
+ final_time=final_time, logmgr=logmgr,
+ max_dt_getter=lambda t: op.estimate_timestep(discr,
+ stepper=stepper, t=t, max_eigenvalue=max_eigval[0]))
+
+ for step, t, dt in step_it:
+ #if step % 10 == 0:
+ if write_output:
+ visf = vis.make_file("sinewave-%d-%04d" % (order, step))
+
+ #from pyvisfile.silo import DB_VARTYPE_VECTOR
+ vis.add_data(visf,
+ [
+ ("rho", discr.convert_volume(op.rho(fields), kind="numpy")),
+ ("e", discr.convert_volume(op.e(fields), kind="numpy")),
+ ("rho_u", discr.convert_volume(op.rho_u(fields), kind="numpy")),
+ ("u", discr.convert_volume(op.u(fields), kind="numpy")),
+
+ #("true_rho", op.rho(true_fields)),
+ #("true_e", op.e(true_fields)),
+ #("true_rho_u", op.rho_u(true_fields)),
+ #("true_u", op.u(true_fields)),
+
+ #("rhs_rho", op.rho(rhs_fields)),
+ #("rhs_e", op.e(rhs_fields)),
+ #("rhs_rho_u", op.rho_u(rhs_fields)),
+ ],
+ #expressions=[
+ #("diff_rho", "rho-true_rho"),
+ #("diff_e", "e-true_e"),
+ #("diff_rho_u", "rho_u-true_rho_u", DB_VARTYPE_VECTOR),
+
+ #("p", "0.4*(e- 0.5*(rho_u*u))"),
+ #],
+ time=t, step=step
+ )
+ visf.close()
+
+ fields = stepper(fields, t, dt, rhs)
+
+ finally:
+ vis.close()
+ logmgr.close()
+ discr.close()
+
+ true_fields = sinewave.volume_interpolant(t, discr)
+ eoc_rec.add_data_point(order, discr.norm(fields-true_fields))
+ print
+ print eoc_rec.pretty_print("P.Deg.", "L2 Error")
+
+
+
+
+if __name__ == "__main__":
+ main()
+
+
+
+
+# entry points for py.test ----------------------------------------------------
+from pytools.test import mark_test
+@mark_test.long
+def test_euler_sine_wave():
+ main(final_time=0.1, write_output=False)
+
diff --git a/examples/gas_dynamics/euler/sod-2d.py b/examples/gas_dynamics/euler/sod-2d.py
new file mode 100644
index 0000000000000000000000000000000000000000..352a855e8c9bf12df6729b8384e7976e2fb34fbc
--- /dev/null
+++ b/examples/gas_dynamics/euler/sod-2d.py
@@ -0,0 +1,183 @@
+from __future__ import division
+import numpy
+import numpy.linalg as la
+
+
+
+
+class Sod:
+ def __init__(self, gamma):
+ self.gamma = gamma
+ self.prandtl = 0.72
+
+ def __call__(self, t, x_vec):
+
+ from hedge.tools import heaviside
+ from hedge.tools import heaviside_a
+
+ x_rel = x_vec[0]
+ y_rel = x_vec[1]
+
+ from math import pi
+ r = numpy.sqrt(x_rel**2+y_rel**2)
+ r_shift=r-3.0
+ u = 0.0
+ v = 0.0
+ from numpy import sign
+ rho = heaviside(-r_shift)+.125*heaviside_a(r_shift,1.0)
+ e = (1.0/(self.gamma-1.0))*(heaviside(-r_shift)+.1*heaviside_a(r_shift,1.0))
+ p = (self.gamma-1.0)*e
+
+ from hedge.tools import join_fields
+ return join_fields(rho, e, rho*u, rho*v)
+
+
+ def volume_interpolant(self, t, discr):
+ return discr.convert_volume(
+ self(t, discr.nodes.T),
+ kind=discr.compute_kind)
+
+ def boundary_interpolant(self, t, discr, tag):
+ return discr.convert_boundary(
+ self(t, discr.get_boundary(tag).nodes.T),
+ tag=tag, kind=discr.compute_kind)
+
+
+
+
+def main():
+ from hedge.backends import guess_run_context
+ rcon = guess_run_context()
+
+ from hedge.tools import to_obj_array
+
+ if rcon.is_head_rank:
+ from hedge.mesh.generator import make_rect_mesh
+ mesh = make_rect_mesh((-5,-5), (5,5), max_area=0.01)
+ mesh_data = rcon.distribute_mesh(mesh)
+ else:
+ mesh_data = rcon.receive_mesh()
+
+ for order in [1]:
+ discr = rcon.make_discretization(mesh_data, order=order,
+ default_scalar_type=numpy.float64)
+
+ from hedge.visualization import SiloVisualizer, VtkVisualizer
+ vis = VtkVisualizer(discr, rcon, "Sod2D-%d" % order)
+ #vis = SiloVisualizer(discr, rcon)
+
+ sod_field = Sod(gamma=1.4)
+ fields = sod_field.volume_interpolant(0, discr)
+
+ from hedge.models.gas_dynamics import GasDynamicsOperator
+ from hedge.mesh import TAG_ALL
+ op = GasDynamicsOperator(dimensions=2, gamma=sod_field.gamma, mu=0.0,
+ prandtl=sod_field.prandtl,
+ bc_inflow=sod_field,
+ bc_outflow=sod_field,
+ bc_noslip=sod_field,
+ inflow_tag=TAG_ALL,
+ source=None)
+
+ euler_ex = op.bind(discr)
+
+ max_eigval = [0]
+ def rhs(t, q):
+ ode_rhs, speed = euler_ex(t, q)
+ max_eigval[0] = speed
+ return ode_rhs
+ rhs(0, fields)
+
+ if rcon.is_head_rank:
+ print "---------------------------------------------"
+ print "order %d" % order
+ print "---------------------------------------------"
+ print "#elements=", len(mesh.elements)
+
+ # limiter setup ------------------------------------------------------------
+ from hedge.models.gas_dynamics import SlopeLimiter1NEuler
+ limiter = SlopeLimiter1NEuler(discr, sod_field.gamma, 2, op)
+
+ # integrator setup---------------------------------------------------------
+ from hedge.timestep import SSPRK3TimeStepper, RK4TimeStepper
+ stepper = SSPRK3TimeStepper(limiter=limiter)
+ #stepper = SSPRK3TimeStepper()
+ #stepper = RK4TimeStepper()
+
+ # diagnostics setup ---------------------------------------------------
+ from pytools.log import LogManager, add_general_quantities, \
+ add_simulation_quantities, add_run_info
+
+ logmgr = LogManager("euler-%d.dat" % order, "w", rcon.communicator)
+ add_run_info(logmgr)
+ add_general_quantities(logmgr)
+ add_simulation_quantities(logmgr)
+ discr.add_instrumentation(logmgr)
+ stepper.add_instrumentation(logmgr)
+
+ logmgr.add_watches(["step.max", "t_sim.max", "t_step.max"])
+
+ # filter setup-------------------------------------------------------------
+ from hedge.discretization import Filter, ExponentialFilterResponseFunction
+ mode_filter = Filter(discr,
+ ExponentialFilterResponseFunction(min_amplification=0.9,order=4))
+
+ # timestep loop -------------------------------------------------------
+ try:
+ from hedge.timestep import times_and_steps
+ step_it = times_and_steps(
+ final_time=1.0, logmgr=logmgr,
+ max_dt_getter=lambda t: op.estimate_timestep(discr,
+ stepper=stepper, t=t, max_eigenvalue=max_eigval[0]))
+
+ for step, t, dt in step_it:
+ if step % 5 == 0:
+ #if False:
+ visf = vis.make_file("vortex-%d-%04d" % (order, step))
+
+ #true_fields = vortex.volume_interpolant(t, discr)
+
+ #from pyvisfile.silo import DB_VARTYPE_VECTOR
+ vis.add_data(visf,
+ [
+ ("rho", discr.convert_volume(op.rho(fields), kind="numpy")),
+ ("e", discr.convert_volume(op.e(fields), kind="numpy")),
+ ("rho_u", discr.convert_volume(op.rho_u(fields), kind="numpy")),
+ ("u", discr.convert_volume(op.u(fields), kind="numpy")),
+
+ #("true_rho", op.rho(true_fields)),
+ #("true_e", op.e(true_fields)),
+ #("true_rho_u", op.rho_u(true_fields)),
+ #("true_u", op.u(true_fields)),
+
+ #("rhs_rho", op.rho(rhs_fields)),
+ #("rhs_e", op.e(rhs_fields)),
+ #("rhs_rho_u", op.rho_u(rhs_fields)),
+ ],
+ #expressions=[
+ #("diff_rho", "rho-true_rho"),
+ #("diff_e", "e-true_e"),
+ #("diff_rho_u", "rho_u-true_rho_u", DB_VARTYPE_VECTOR),
+
+ #("p", "0.4*(e- 0.5*(rho_u*u))"),
+ #],
+ time=t, step=step
+ )
+ visf.close()
+
+ fields = stepper(fields, t, dt, rhs)
+ # fields = limiter(fields)
+ # fields = mode_filter(fields)
+
+ assert not numpy.isnan(numpy.sum(fields[0]))
+ finally:
+ vis.close()
+ logmgr.close()
+ discr.close()
+
+ # not solution, just to check against when making code changes
+ true_fields = sod_field.volume_interpolant(t, discr)
+ print discr.norm(fields-true_fields)
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/gas_dynamics/euler/vortex-adaptive-grid.py b/examples/gas_dynamics/euler/vortex-adaptive-grid.py
new file mode 100644
index 0000000000000000000000000000000000000000..fb33c2ed0c1884e1123e50b573f9eb16d2e7c3cb
--- /dev/null
+++ b/examples/gas_dynamics/euler/vortex-adaptive-grid.py
@@ -0,0 +1,258 @@
+# Hedge - the Hybrid'n'Easy DG Environment
+# Copyright (C) 2008 Andreas Kloeckner
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+
+
+
+from __future__ import division
+import numpy
+import numpy.linalg as la
+
+
+
+
+def main(write_output=True):
+ from pytools import add_python_path_relative_to_script
+ add_python_path_relative_to_script("..")
+
+ from hedge.backends import guess_run_context
+ rcon = guess_run_context()
+
+ from hedge.tools import EOCRecorder
+ eoc_rec = EOCRecorder()
+
+
+ if rcon.is_head_rank:
+ from hedge.mesh.generator import \
+ make_rect_mesh, \
+ make_centered_regular_rect_mesh
+
+ refine = 4
+ mesh = make_centered_regular_rect_mesh((0,-5), (10,5), n=(9,9),
+ post_refine_factor=refine)
+ mesh_data = rcon.distribute_mesh(mesh)
+ else:
+ mesh_data = rcon.receive_mesh()
+
+ # a second mesh to regrid to
+ if rcon.is_head_rank:
+ from hedge.mesh.generator import \
+ make_rect_mesh, \
+ make_centered_regular_rect_mesh
+
+ refine = 4
+ mesh2 = make_centered_regular_rect_mesh((0,-5), (10,5), n=(8,8),
+ post_refine_factor=refine)
+ mesh_data2 = rcon.distribute_mesh(mesh2)
+ else:
+ mesh_data2 = rcon.receive_mesh()
+
+
+
+ for order in [3,4]:
+ discr = rcon.make_discretization(mesh_data, order=order,
+ default_scalar_type=numpy.float64,
+ quad_min_degrees={
+ "gasdyn_vol": 3*order,
+ "gasdyn_face": 3*order,
+ })
+
+ discr2 = rcon.make_discretization(mesh_data2, order=order,
+ default_scalar_type=numpy.float64,
+ quad_min_degrees={
+ "gasdyn_vol": 3*order,
+ "gasdyn_face": 3*order,
+ })
+
+
+ from hedge.visualization import SiloVisualizer, VtkVisualizer
+ vis = VtkVisualizer(discr, rcon, "vortex-%d" % order)
+ #vis = SiloVisualizer(discr, rcon)
+
+ from gas_dynamics_initials import Vortex
+ vortex = Vortex()
+ fields = vortex.volume_interpolant(0, discr)
+
+ from hedge.models.gas_dynamics import GasDynamicsOperator
+ from hedge.mesh import TAG_ALL
+
+ op = GasDynamicsOperator(dimensions=2, gamma=vortex.gamma, mu=vortex.mu,
+ prandtl=vortex.prandtl, spec_gas_const=vortex.spec_gas_const,
+ bc_inflow=vortex, bc_outflow=vortex, bc_noslip=vortex,
+ inflow_tag=TAG_ALL, source=None)
+
+ euler_ex = op.bind(discr)
+
+ max_eigval = [0]
+ def rhs(t, q):
+ ode_rhs, speed = euler_ex(t, q)
+ max_eigval[0] = speed
+ return ode_rhs
+ rhs(0, fields)
+
+
+ if rcon.is_head_rank:
+ print "---------------------------------------------"
+ print "order %d" % order
+ print "---------------------------------------------"
+ print "#elements for mesh 1 =", len(mesh.elements)
+ print "#elements for mesh 2 =", len(mesh2.elements)
+
+
+ # limiter ------------------------------------------------------------
+ from hedge.models.gas_dynamics import SlopeLimiter1NEuler
+ limiter = SlopeLimiter1NEuler(discr, vortex.gamma, 2, op)
+
+ from hedge.timestep import SSPRK3TimeStepper
+ #stepper = SSPRK3TimeStepper(limiter=limiter)
+ stepper = SSPRK3TimeStepper()
+
+ #from hedge.timestep import RK4TimeStepper
+ #stepper = RK4TimeStepper()
+
+ # diagnostics setup ---------------------------------------------------
+ from pytools.log import LogManager, add_general_quantities, \
+ add_simulation_quantities, add_run_info
+
+ if write_output:
+ log_file_name = "euler-%d.dat" % order
+ else:
+ log_file_name = None
+
+ logmgr = LogManager(log_file_name, "w", rcon.communicator)
+ add_run_info(logmgr)
+ add_general_quantities(logmgr)
+ add_simulation_quantities(logmgr)
+ discr.add_instrumentation(logmgr)
+ stepper.add_instrumentation(logmgr)
+
+ logmgr.add_watches(["step.max", "t_sim.max", "t_step.max"])
+
+ # timestep loop -------------------------------------------------------
+ try:
+ final_time = 0.2
+ from hedge.timestep import times_and_steps
+ step_it = times_and_steps(
+ final_time=final_time, logmgr=logmgr,
+ max_dt_getter=lambda t: op.estimate_timestep(discr,
+ stepper=stepper, t=t, max_eigenvalue=max_eigval[0]))
+
+ for step, t, dt in step_it:
+ if step % 10 == 0 and write_output:
+ #if False:
+ visf = vis.make_file("vortex-%d-%04d" % (order, step))
+
+ #true_fields = vortex.volume_interpolant(t, discr)
+
+ from pyvisfile.silo import DB_VARTYPE_VECTOR
+ vis.add_data(visf,
+ [
+ ("rho", discr.convert_volume(op.rho(fields), kind="numpy")),
+ ("e", discr.convert_volume(op.e(fields), kind="numpy")),
+ ("rho_u", discr.convert_volume(op.rho_u(fields), kind="numpy")),
+ ("u", discr.convert_volume(op.u(fields), kind="numpy")),
+
+ #("true_rho", discr.convert_volume(op.rho(true_fields), kind="numpy")),
+ #("true_e", discr.convert_volume(op.e(true_fields), kind="numpy")),
+ #("true_rho_u", discr.convert_volume(op.rho_u(true_fields), kind="numpy")),
+ #("true_u", discr.convert_volume(op.u(true_fields), kind="numpy")),
+
+ #("rhs_rho", discr.convert_volume(op.rho(rhs_fields), kind="numpy")),
+ #("rhs_e", discr.convert_volume(op.e(rhs_fields), kind="numpy")),
+ #("rhs_rho_u", discr.convert_volume(op.rho_u(rhs_fields), kind="numpy")),
+ ],
+ #expressions=[
+ #("diff_rho", "rho-true_rho"),
+ #("diff_e", "e-true_e"),
+ #("diff_rho_u", "rho_u-true_rho_u", DB_VARTYPE_VECTOR),
+
+ #("p", "0.4*(e- 0.5*(rho_u*u))"),
+ #],
+ time=t, step=step
+ )
+ visf.close()
+
+ fields = stepper(fields, t, dt, rhs)
+ #fields = limiter(fields)
+
+ #regrid to discr2 at some arbitrary time
+ if step == 21:
+
+ #get interpolated fields
+ fields = discr.get_regrid_values(fields, discr2, dtype=None, use_btree=True, thresh=1e-8)
+ #get new stepper (old one has reference to discr
+ stepper = SSPRK3TimeStepper()
+ #new bind
+ euler_ex = op.bind(discr2)
+ #new rhs
+ max_eigval = [0]
+ def rhs(t, q):
+ ode_rhs, speed = euler_ex(t, q)
+ max_eigval[0] = speed
+ return ode_rhs
+ rhs(t+dt, fields)
+ #add logmanager
+ #discr2.add_instrumentation(logmgr)
+ #new step_it
+ step_it = times_and_steps(
+ final_time=final_time, logmgr=logmgr,
+ max_dt_getter=lambda t: op.estimate_timestep(discr2,
+ stepper=stepper, t=t, max_eigenvalue=max_eigval[0]))
+
+ #new visualization
+ vis.close()
+ vis = VtkVisualizer(discr2, rcon, "vortexNewGrid-%d" % order)
+ discr=discr2
+
+
+
+ assert not numpy.isnan(numpy.sum(fields[0]))
+
+ true_fields = vortex.volume_interpolant(final_time, discr)
+ l2_error = discr.norm(fields-true_fields)
+ l2_error_rho = discr.norm(op.rho(fields)-op.rho(true_fields))
+ l2_error_e = discr.norm(op.e(fields)-op.e(true_fields))
+ l2_error_rhou = discr.norm(op.rho_u(fields)-op.rho_u(true_fields))
+ l2_error_u = discr.norm(op.u(fields)-op.u(true_fields))
+
+ eoc_rec.add_data_point(order, l2_error)
+ print
+ print eoc_rec.pretty_print("P.Deg.", "L2 Error")
+
+ logmgr.set_constant("l2_error", l2_error)
+ logmgr.set_constant("l2_error_rho", l2_error_rho)
+ logmgr.set_constant("l2_error_e", l2_error_e)
+ logmgr.set_constant("l2_error_rhou", l2_error_rhou)
+ logmgr.set_constant("l2_error_u", l2_error_u)
+ logmgr.set_constant("refinement", refine)
+
+ finally:
+ if write_output:
+ vis.close()
+
+ logmgr.close()
+ discr.close()
+
+
+
+ # after order loop
+ # assert eoc_rec.estimate_order_of_convergence()[0,1] > 6
+
+
+
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/gas_dynamics/euler/vortex-sources.py b/examples/gas_dynamics/euler/vortex-sources.py
new file mode 100644
index 0000000000000000000000000000000000000000..dbe5f84d57bbcd7722cf925708c4904b30196403
--- /dev/null
+++ b/examples/gas_dynamics/euler/vortex-sources.py
@@ -0,0 +1,334 @@
+# Hedge - the Hybrid'n'Easy DG Environment
+# Copyright (C) 2008 Andreas Kloeckner
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+
+
+
+from __future__ import division
+import numpy
+import numpy.linalg as la
+
+# modifies isentropic vortex solution so that rho->Arho, P->A^gamma rho^gamma
+# this will be analytic solution if appropriate source terms are added
+# to the RHS. coded for vel_x=1, vel_y=0
+
+
+class Vortex:
+ def __init__(self, beta, gamma, center, velocity, densityA):
+ self.beta = beta
+ self.gamma = gamma
+ self.center = numpy.asarray(center)
+ self.velocity = numpy.asarray(velocity)
+ self.densityA = densityA
+
+ def __call__(self, t, x_vec):
+ vortex_loc = self.center + t*self.velocity
+
+ # coordinates relative to vortex center
+ x_rel = x_vec[0] - vortex_loc[0]
+ y_rel = x_vec[1] - vortex_loc[1]
+
+ # Y.C. Zhou, G.W. Wei / Journal of Computational Physics 189 (2003) 159
+ # also JSH/TW Nodal DG Methods, p. 209
+
+ from math import pi
+ r = numpy.sqrt(x_rel**2+y_rel**2)
+ expterm = self.beta*numpy.exp(1-r**2)
+ u = self.velocity[0] - expterm*y_rel/(2*pi)
+ v = self.velocity[1] + expterm*x_rel/(2*pi)
+ rho = self.densityA*(1-(self.gamma-1)/(16*self.gamma*pi**2)*expterm**2)**(1/(self.gamma-1))
+ p = rho**self.gamma
+
+ e = p/(self.gamma-1) + rho/2*(u**2+v**2)
+
+ from hedge.tools import join_fields
+ return join_fields(rho, e, rho*u, rho*v)
+
+ def volume_interpolant(self, t, discr):
+ return discr.convert_volume(
+ self(t, discr.nodes.T
+ .astype(discr.default_scalar_type)),
+ kind=discr.compute_kind)
+
+ def boundary_interpolant(self, t, discr, tag):
+ return discr.convert_boundary(
+ self(t, discr.get_boundary(tag).nodes.T
+ .astype(discr.default_scalar_type)),
+ tag=tag, kind=discr.compute_kind)
+
+
+
+class SourceTerms:
+ def __init__(self, beta, gamma, center, velocity, densityA):
+ self.beta = beta
+ self.gamma = gamma
+ self.center = numpy.asarray(center)
+ self.velocity = numpy.asarray(velocity)
+ self.densityA = densityA
+
+
+
+ def __call__(self,t,x_vec,q):
+
+ vortex_loc = self.center + t*self.velocity
+
+ # coordinates relative to vortex center
+ x_rel = x_vec[0] - vortex_loc[0]
+ y_rel = x_vec[1] - vortex_loc[1]
+
+ # sources written in terms of A=1.0 solution
+ # (standard isentropic vortex)
+
+ from math import pi
+ r = numpy.sqrt(x_rel**2+y_rel**2)
+ expterm = self.beta*numpy.exp(1-r**2)
+ u = self.velocity[0] - expterm*y_rel/(2*pi)
+ v = self.velocity[1] + expterm*x_rel/(2*pi)
+ rho = (1-(self.gamma-1)/(16*self.gamma*pi**2)*expterm**2)**(1/(self.gamma-1))
+ p = rho**self.gamma
+
+ #computed necessary derivatives
+ expterm_t = 2*expterm*x_rel
+ expterm_x = -2*expterm*x_rel
+ expterm_y = -2*expterm*y_rel
+ u_x = -expterm*y_rel/(2*pi)*(-2*x_rel)
+ v_y = expterm*x_rel/(2*pi)*(-2*y_rel)
+
+ #derivatives for rho (A=1)
+ facG=self.gamma-1
+ rho_t = (1/facG)*(1-(facG)/(16*self.gamma*pi**2)*expterm**2)**(1/facG-1)* \
+ (-facG/(16*self.gamma*pi**2)*2*expterm*expterm_t)
+ rho_x = (1/facG)*(1-(facG)/(16*self.gamma*pi**2)*expterm**2)**(1/facG-1)* \
+ (-facG/(16*self.gamma*pi**2)*2*expterm*expterm_x)
+ rho_y = (1/facG)*(1-(facG)/(16*self.gamma*pi**2)*expterm**2)**(1/facG-1)* \
+ (-facG/(16*self.gamma*pi**2)*2*expterm*expterm_y)
+
+ #derivatives for rho (A=1) to the power of gamma
+ rho_gamma_t = self.gamma*rho**(self.gamma-1)*rho_t
+ rho_gamma_x = self.gamma*rho**(self.gamma-1)*rho_x
+ rho_gamma_y = self.gamma*rho**(self.gamma-1)*rho_y
+
+
+ factorA=self.densityA**self.gamma-self.densityA
+ #construct source terms
+ source_rho = x_vec[0]-x_vec[0]
+ source_e = (factorA/(self.gamma-1))*(rho_gamma_t + self.gamma*(u_x*rho**self.gamma+u*rho_gamma_x)+ \
+ self.gamma*(v_y*rho**self.gamma+v*rho_gamma_y))
+ source_rhou = factorA*rho_gamma_x
+ source_rhov = factorA*rho_gamma_y
+
+ from hedge.tools import join_fields
+ return join_fields(source_rho, source_e, source_rhou, source_rhov, x_vec[0]-x_vec[0])
+
+ def volume_interpolant(self,t,q,discr):
+ return discr.convert_volume(
+ self(t,discr.nodes.T,q),
+ kind=discr.compute_kind)
+
+
+def main(write_output=True):
+ from hedge.backends import guess_run_context
+ rcon = guess_run_context(
+ #["cuda"]
+ )
+
+ gamma = 1.4
+
+ # at A=1 we have case of isentropic vortex, source terms
+ # arise for other values
+ densityA = 2.0
+
+ from hedge.tools import EOCRecorder, to_obj_array
+ eoc_rec = EOCRecorder()
+
+ if rcon.is_head_rank:
+ from hedge.mesh import \
+ make_rect_mesh, \
+ make_centered_regular_rect_mesh
+
+ refine = 1
+ mesh = make_centered_regular_rect_mesh((0,-5), (10,5), n=(9,9),
+ post_refine_factor=refine)
+ mesh_data = rcon.distribute_mesh(mesh)
+ else:
+ mesh_data = rcon.receive_mesh()
+
+ for order in [4,5]:
+ discr = rcon.make_discretization(mesh_data, order=order,
+ debug=[#"cuda_no_plan",
+ #"print_op_code"
+ ],
+ default_scalar_type=numpy.float64)
+
+ from hedge.visualization import SiloVisualizer, VtkVisualizer
+ #vis = VtkVisualizer(discr, rcon, "vortex-%d" % order)
+ vis = SiloVisualizer(discr, rcon)
+
+ vortex = Vortex(beta=5, gamma=gamma,
+ center=[5,0],
+ velocity=[1,0], densityA=densityA)
+ fields = vortex.volume_interpolant(0, discr)
+ sources=SourceTerms(beta=5, gamma=gamma,
+ center=[5,0],
+ velocity=[1,0], densityA=densityA)
+
+ from hedge.models.gas_dynamics import (
+ GasDynamicsOperator, GammaLawEOS)
+ from hedge.mesh import TAG_ALL
+
+ op = GasDynamicsOperator(dimensions=2,
+ mu=0.0, prandtl=0.72, spec_gas_const=287.1,
+ equation_of_state=GammaLawEOS(vortex.gamma),
+ bc_inflow=vortex, bc_outflow=vortex, bc_noslip=vortex,
+ inflow_tag=TAG_ALL, source=sources)
+
+ euler_ex = op.bind(discr)
+
+ max_eigval = [0]
+ def rhs(t, q):
+ ode_rhs, speed = euler_ex(t, q)
+ max_eigval[0] = speed
+ return ode_rhs
+ rhs(0, fields)
+
+ if rcon.is_head_rank:
+ print "---------------------------------------------"
+ print "order %d" % order
+ print "---------------------------------------------"
+ print "#elements=", len(mesh.elements)
+
+ # limiter setup -------------------------------------------------------
+ from hedge.models.gas_dynamics import SlopeLimiter1NEuler
+ limiter = SlopeLimiter1NEuler(discr, gamma, 2, op)
+
+ # time stepper --------------------------------------------------------
+ from hedge.timestep import SSPRK3TimeStepper, RK4TimeStepper
+ #stepper = SSPRK3TimeStepper(limiter=limiter)
+ #stepper = SSPRK3TimeStepper()
+ stepper = RK4TimeStepper()
+
+ # diagnostics setup ---------------------------------------------------
+ from pytools.log import LogManager, add_general_quantities, \
+ add_simulation_quantities, add_run_info
+
+ if write_output:
+ log_file_name = "euler-%d.dat" % order
+ else:
+ log_file_name = None
+
+ logmgr = LogManager(log_file_name, "w", rcon.communicator)
+ add_run_info(logmgr)
+ add_general_quantities(logmgr)
+ add_simulation_quantities(logmgr)
+ discr.add_instrumentation(logmgr)
+ stepper.add_instrumentation(logmgr)
+
+ logmgr.add_watches(["step.max", "t_sim.max", "t_step.max"])
+
+ # timestep loop -------------------------------------------------------
+ t = 0
+
+ #fields = limiter(fields)
+
+ try:
+ from hedge.timestep import times_and_steps
+ step_it = times_and_steps(
+ final_time=.1,
+ #max_steps=500,
+ logmgr=logmgr,
+ max_dt_getter=lambda t: 0.4*op.estimate_timestep(discr,
+ stepper=stepper, t=t, max_eigenvalue=max_eigval[0]))
+
+ for step, t, dt in step_it:
+ if step % 1 == 0 and write_output:
+ #if False:
+ visf = vis.make_file("vortex-%d-%04d" % (order, step))
+
+ true_fields = vortex.volume_interpolant(t, discr)
+
+ #rhs_fields = rhs(t, fields)
+
+ from pyvisfile.silo import DB_VARTYPE_VECTOR
+ vis.add_data(visf,
+ [
+ ("rho", discr.convert_volume(op.rho(fields), kind="numpy")),
+ ("e", discr.convert_volume(op.e(fields), kind="numpy")),
+ ("rho_u", discr.convert_volume(op.rho_u(fields), kind="numpy")),
+ ("u", discr.convert_volume(op.u(fields), kind="numpy")),
+
+ #("true_rho", discr.convert_volume(op.rho(true_fields), kind="numpy")),
+ #("true_e", discr.convert_volume(op.e(true_fields), kind="numpy")),
+ #("true_rho_u", discr.convert_volume(op.rho_u(true_fields), kind="numpy")),
+ #("true_u", discr.convert_volume(op.u(true_fields), kind="numpy")),
+
+ #("rhs_rho", discr.convert_volume(op.rho(rhs_fields), kind="numpy")),
+ #("rhs_e", discr.convert_volume(op.e(rhs_fields), kind="numpy")),
+ #("rhs_rho_u", discr.convert_volume(op.rho_u(rhs_fields), kind="numpy")),
+ ],
+ expressions=[
+ #("diff_rho", "rho-true_rho"),
+ #("diff_e", "e-true_e"),
+ #("diff_rho_u", "rho_u-true_rho_u", DB_VARTYPE_VECTOR),
+
+ ("p", "0.4*(e- 0.5*(rho_u*u))"),
+ ],
+ time=t, step=step
+ )
+ visf.close()
+
+ fields = stepper(fields, t, dt, rhs)
+
+ true_fields = vortex.volume_interpolant(t, discr)
+ l2_error = discr.norm(fields-true_fields)
+ l2_error_rho = discr.norm(op.rho(fields)-op.rho(true_fields))
+ l2_error_e = discr.norm(op.e(fields)-op.e(true_fields))
+ l2_error_rhou = discr.norm(op.rho_u(fields)-op.rho_u(true_fields))
+ l2_error_u = discr.norm(op.u(fields)-op.u(true_fields))
+
+ eoc_rec.add_data_point(order, l2_error_rho)
+ print
+ print eoc_rec.pretty_print("P.Deg.", "L2 Error")
+
+ logmgr.set_constant("l2_error", l2_error)
+ logmgr.set_constant("l2_error_rho", l2_error_rho)
+ logmgr.set_constant("l2_error_e", l2_error_e)
+ logmgr.set_constant("l2_error_rhou", l2_error_rhou)
+ logmgr.set_constant("l2_error_u", l2_error_u)
+ logmgr.set_constant("refinement", refine)
+
+ finally:
+ if write_output:
+ vis.close()
+
+ logmgr.close()
+ discr.close()
+
+ # after order loop
+ #assert eoc_rec.estimate_order_of_convergence()[0,1] > 6
+
+
+
+
+if __name__ == "__main__":
+ main()
+
+
+
+# entry points for py.test ----------------------------------------------------
+from pytools.test import mark_test
+@mark_test.long
+def test_euler_vortex():
+ main(write_output=False)
diff --git a/examples/gas_dynamics/euler/vortex.py b/examples/gas_dynamics/euler/vortex.py
new file mode 100644
index 0000000000000000000000000000000000000000..ddbb43288692bd7807c5bd4a7b6779a817ba994b
--- /dev/null
+++ b/examples/gas_dynamics/euler/vortex.py
@@ -0,0 +1,214 @@
+# Hedge - the Hybrid'n'Easy DG Environment
+# Copyright (C) 2008 Andreas Kloeckner
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+
+
+
+from __future__ import division
+import numpy
+
+
+
+
+def main(write_output=True):
+ from pytools import add_python_path_relative_to_script
+ add_python_path_relative_to_script("..")
+
+ from hedge.backends import guess_run_context
+ rcon = guess_run_context()
+
+ from hedge.tools import EOCRecorder
+ eoc_rec = EOCRecorder()
+
+ if rcon.is_head_rank:
+ from hedge.mesh.generator import \
+ make_rect_mesh, \
+ make_centered_regular_rect_mesh
+
+ refine = 4
+ mesh = make_centered_regular_rect_mesh((0,-5), (10,5), n=(9,9),
+ post_refine_factor=refine)
+ mesh_data = rcon.distribute_mesh(mesh)
+ else:
+ mesh_data = rcon.receive_mesh()
+
+ for order in [3, 4, 5]:
+ from gas_dynamics_initials import Vortex
+ flow = Vortex()
+
+ from hedge.models.gas_dynamics import (
+ GasDynamicsOperator, PolytropeEOS, GammaLawEOS)
+
+ from hedge.mesh import TAG_ALL
+ # works equally well for GammaLawEOS
+ op = GasDynamicsOperator(dimensions=2, mu=flow.mu,
+ prandtl=flow.prandtl, spec_gas_const=flow.spec_gas_const,
+ equation_of_state=PolytropeEOS(flow.gamma),
+ bc_inflow=flow, bc_outflow=flow, bc_noslip=flow,
+ inflow_tag=TAG_ALL, source=None)
+
+ discr = rcon.make_discretization(mesh_data, order=order,
+ default_scalar_type=numpy.float64,
+ quad_min_degrees={
+ "gasdyn_vol": 3*order,
+ "gasdyn_face": 3*order,
+ },
+ tune_for=op.op_template(),
+ debug=["cuda_no_plan"])
+
+ from hedge.visualization import SiloVisualizer, VtkVisualizer
+ vis = VtkVisualizer(discr, rcon, "vortex-%d" % order)
+ #vis = SiloVisualizer(discr, rcon)
+
+ fields = flow.volume_interpolant(0, discr)
+
+ euler_ex = op.bind(discr)
+
+ max_eigval = [0]
+ def rhs(t, q):
+ ode_rhs, speed = euler_ex(t, q)
+ max_eigval[0] = speed
+ return ode_rhs
+ rhs(0, fields)
+
+ if rcon.is_head_rank:
+ print "---------------------------------------------"
+ print "order %d" % order
+ print "---------------------------------------------"
+ print "#elements=", len(mesh.elements)
+
+
+ # limiter ------------------------------------------------------------
+ from hedge.models.gas_dynamics import SlopeLimiter1NEuler
+ limiter = SlopeLimiter1NEuler(discr, flow.gamma, 2, op)
+
+ from hedge.timestep.runge_kutta import SSP3TimeStepper
+ #stepper = SSP3TimeStepper(limiter=limiter)
+ stepper = SSP3TimeStepper(
+ vector_primitive_factory=discr.get_vector_primitive_factory())
+
+ #from hedge.timestep import RK4TimeStepper
+ #stepper = RK4TimeStepper()
+
+ # diagnostics setup ---------------------------------------------------
+ from pytools.log import LogManager, add_general_quantities, \
+ add_simulation_quantities, add_run_info
+
+ if write_output:
+ log_file_name = "euler-%d.dat" % order
+ else:
+ log_file_name = None
+
+ logmgr = LogManager(log_file_name, "w", rcon.communicator)
+ add_run_info(logmgr)
+ add_general_quantities(logmgr)
+ add_simulation_quantities(logmgr)
+ discr.add_instrumentation(logmgr)
+ stepper.add_instrumentation(logmgr)
+
+ logmgr.add_watches(["step.max", "t_sim.max", "t_step.max"])
+
+ # timestep loop -------------------------------------------------------
+ try:
+ final_time = flow.final_time
+ from hedge.timestep import times_and_steps
+ step_it = times_and_steps(
+ final_time=final_time, logmgr=logmgr,
+ max_dt_getter=lambda t: op.estimate_timestep(discr,
+ stepper=stepper, t=t, max_eigenvalue=max_eigval[0]))
+
+ print "run until t=%g" % final_time
+ for step, t, dt in step_it:
+ if step % 10 == 0 and write_output:
+ #if False:
+ visf = vis.make_file("vortex-%d-%04d" % (order, step))
+
+ #true_fields = vortex.volume_interpolant(t, discr)
+
+ from pyvisfile.silo import DB_VARTYPE_VECTOR
+ vis.add_data(visf,
+ [
+ ("rho", discr.convert_volume(op.rho(fields), kind="numpy")),
+ ("e", discr.convert_volume(op.e(fields), kind="numpy")),
+ ("rho_u", discr.convert_volume(op.rho_u(fields), kind="numpy")),
+ ("u", discr.convert_volume(op.u(fields), kind="numpy")),
+
+ #("true_rho", discr.convert_volume(op.rho(true_fields), kind="numpy")),
+ #("true_e", discr.convert_volume(op.e(true_fields), kind="numpy")),
+ #("true_rho_u", discr.convert_volume(op.rho_u(true_fields), kind="numpy")),
+ #("true_u", discr.convert_volume(op.u(true_fields), kind="numpy")),
+
+ #("rhs_rho", discr.convert_volume(op.rho(rhs_fields), kind="numpy")),
+ #("rhs_e", discr.convert_volume(op.e(rhs_fields), kind="numpy")),
+ #("rhs_rho_u", discr.convert_volume(op.rho_u(rhs_fields), kind="numpy")),
+ ],
+ #expressions=[
+ #("diff_rho", "rho-true_rho"),
+ #("diff_e", "e-true_e"),
+ #("diff_rho_u", "rho_u-true_rho_u", DB_VARTYPE_VECTOR),
+
+ #("p", "0.4*(e- 0.5*(rho_u*u))"),
+ #],
+ time=t, step=step
+ )
+ visf.close()
+
+ fields = stepper(fields, t, dt, rhs)
+ #fields = limiter(fields)
+
+ assert not numpy.isnan(numpy.sum(fields[0]))
+
+ true_fields = flow.volume_interpolant(final_time, discr)
+ l2_error = discr.norm(fields-true_fields)
+ l2_error_rho = discr.norm(op.rho(fields)-op.rho(true_fields))
+ l2_error_e = discr.norm(op.e(fields)-op.e(true_fields))
+ l2_error_rhou = discr.norm(op.rho_u(fields)-op.rho_u(true_fields))
+ l2_error_u = discr.norm(op.u(fields)-op.u(true_fields))
+
+ eoc_rec.add_data_point(order, l2_error)
+ print
+ print eoc_rec.pretty_print("P.Deg.", "L2 Error")
+
+ logmgr.set_constant("l2_error", l2_error)
+ logmgr.set_constant("l2_error_rho", l2_error_rho)
+ logmgr.set_constant("l2_error_e", l2_error_e)
+ logmgr.set_constant("l2_error_rhou", l2_error_rhou)
+ logmgr.set_constant("l2_error_u", l2_error_u)
+ logmgr.set_constant("refinement", refine)
+
+ finally:
+ if write_output:
+ vis.close()
+
+ logmgr.close()
+ discr.close()
+
+ # after order loop
+ assert eoc_rec.estimate_order_of_convergence()[0,1] > 6
+
+
+
+
+if __name__ == "__main__":
+ main()
+
+
+
+# entry points for py.test ----------------------------------------------------
+from pytools.test import mark_test
+@mark_test.long
+def test_euler_vortex():
+ main(write_output=False)
diff --git a/examples/gas_dynamics/gas_dynamics_initials.py b/examples/gas_dynamics/gas_dynamics_initials.py
new file mode 100644
index 0000000000000000000000000000000000000000..9e1bef7d7cd7b7936fbe3a6b6856c7a211e66743
--- /dev/null
+++ b/examples/gas_dynamics/gas_dynamics_initials.py
@@ -0,0 +1,223 @@
+# Hedge - the Hybrid'n'Easy DG Environment
+# Copyright (C) 2008 Andreas Kloeckner
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+
+
+
+from __future__ import division
+import numpy
+import numpy.linalg as la
+
+
+
+
+class UniformMachFlow:
+ def __init__(self, mach=0.1, p=1, rho=1, reynolds=100,
+ gamma=1.4, prandtl=0.72, char_length=1, spec_gas_const=287.1,
+ angle_of_attack=None, direction=None, gaussian_pulse_at=None,
+ pulse_magnitude=0.1):
+ """
+ :param direction: is a vector indicating the direction of the
+ flow. Only one of angle_of_attack and direction may be
+ specified. Only the direction, not the magnitude, of
+ direction is taken into account.
+
+ :param angle_of_attack: if not None, specifies the angle of
+ the flow along the Y axis, where the flow is
+ directed along the X axis.
+ """
+ if angle_of_attack is not None and direction is not None:
+ raise ValueError("Only one of angle_of_attack and "
+ "direction may be specified.")
+
+ if angle_of_attack is None and direction is None:
+ angle_of_attack = 0
+
+ if direction is not None:
+ self.direction = direction/la.norm(direction)
+ else:
+ self.direction = None
+
+ self.mach = mach
+ self.p = p
+ self.rho = rho
+
+ self.gamma = gamma
+ self.prandtl = prandtl
+ self.reynolds = reynolds
+ self.length = char_length
+ self.spec_gas_const = spec_gas_const
+
+ self.angle_of_attack = angle_of_attack
+
+ self.gaussian_pulse_at = gaussian_pulse_at
+ self.pulse_magnitude = pulse_magnitude
+
+ self.c = (self.gamma * p / rho)**0.5
+ u = self.velocity = mach * self.c
+ self.e = p / (self.gamma - 1) + rho / 2 * u**2
+
+ if numpy.isinf(self.reynolds):
+ self.mu = 0
+ else:
+ self.mu = u * self.length * rho / self.reynolds
+
+ def direction_vector(self, dimensions):
+ # this must be done here because dimensions is not known above
+ if self.direction is None:
+ assert self.angle_of_attack is not None
+ direction = numpy.zeros(dimensions, dtype=numpy.float64)
+ direction[0] = numpy.cos(
+ self.angle_of_attack / 180. * numpy.pi)
+ direction[1] = numpy.sin(
+ self.angle_of_attack / 180. * numpy.pi)
+ return direction
+ else:
+ return self.direction
+
+ def __call__(self, t, x_vec):
+ ones = numpy.ones_like(x_vec[0])
+ rho_field = ones*self.rho
+
+ if self.gaussian_pulse_at is not None:
+ rel_to_pulse = [x_vec[i] - self.gaussian_pulse_at[i]
+ for i in range(len(x_vec))]
+ rho_field += self.pulse_magnitude * self.rho * numpy.exp(
+ - sum(rtp_i**2 for rtp_i in rel_to_pulse)/2)
+
+ direction = self.direction_vector(x_vec.shape[0])
+
+ from hedge.tools import make_obj_array
+ u_field = make_obj_array([ones*self.velocity*dir_i
+ for dir_i in direction])
+
+ from hedge.tools import join_fields
+ return join_fields(rho_field, self.e*ones, self.rho*u_field)
+
+ def volume_interpolant(self, t, discr):
+ return discr.convert_volume(
+ self(t, discr.nodes.T),
+ kind=discr.compute_kind,
+ dtype=discr.default_scalar_type)
+
+ def boundary_interpolant(self, t, discr, tag):
+ return discr.convert_boundary(
+ self(t, discr.get_boundary(tag).nodes.T),
+ tag=tag, kind=discr.compute_kind,
+ dtype=discr.default_scalar_type)
+
+class Vortex:
+ def __init__(self):
+ self.beta = 5
+ self.gamma = 1.4
+ self.center = numpy.array([5, 0])
+ self.velocity = numpy.array([1, 0])
+
+ self.mu = 0
+ self.prandtl = 0.72
+ self.spec_gas_const = 287.1
+
+ def __call__(self, t, x_vec):
+ vortex_loc = self.center + t*self.velocity
+
+ # coordinates relative to vortex center
+ x_rel = x_vec[0] - vortex_loc[0]
+ y_rel = x_vec[1] - vortex_loc[1]
+
+ # Y.C. Zhou, G.W. Wei / Journal of Computational Physics 189 (2003) 159
+ # also JSH/TW Nodal DG Methods, p. 209
+
+ from math import pi
+ r = numpy.sqrt(x_rel**2+y_rel**2)
+ expterm = self.beta*numpy.exp(1-r**2)
+ u = self.velocity[0] - expterm*y_rel/(2*pi)
+ v = self.velocity[1] + expterm*x_rel/(2*pi)
+ rho = (1-(self.gamma-1)/(16*self.gamma*pi**2)*expterm**2)**(1/(self.gamma-1))
+ p = rho**self.gamma
+
+ e = p/(self.gamma-1) + rho/2*(u**2+v**2)
+
+ from hedge.tools import join_fields
+ return join_fields(rho, e, rho*u, rho*v)
+
+ def volume_interpolant(self, t, discr):
+ return discr.convert_volume(
+ self(t, discr.nodes.T
+ .astype(discr.default_scalar_type)),
+ kind=discr.compute_kind)
+
+ def boundary_interpolant(self, t, discr, tag):
+ return discr.convert_boundary(
+ self(t, discr.get_boundary(tag).nodes.T
+ .astype(discr.default_scalar_type)),
+ tag=tag, kind=discr.compute_kind)
+
+
+
+
+
+
+
+class Vortex:
+ def __init__(self):
+ self.beta = 5
+ self.gamma = 1.4
+ self.center = numpy.array([5, 0])
+ self.velocity = numpy.array([1, 0])
+ self.final_time = 0.5
+
+ self.mu = 0
+ self.prandtl = 0.72
+ self.spec_gas_const = 287.1
+
+ def __call__(self, t, x_vec):
+ vortex_loc = self.center + t*self.velocity
+
+ # coordinates relative to vortex center
+ x_rel = x_vec[0] - vortex_loc[0]
+ y_rel = x_vec[1] - vortex_loc[1]
+
+ # Y.C. Zhou, G.W. Wei / Journal of Computational Physics 189 (2003) 159
+ # also JSH/TW Nodal DG Methods, p. 209
+
+ from math import pi
+ r = numpy.sqrt(x_rel**2+y_rel**2)
+ expterm = self.beta*numpy.exp(1-r**2)
+ u = self.velocity[0] - expterm*y_rel/(2*pi)
+ v = self.velocity[1] + expterm*x_rel/(2*pi)
+ rho = (1-(self.gamma-1)/(16*self.gamma*pi**2)*expterm**2)**(1/(self.gamma-1))
+ p = rho**self.gamma
+
+ e = p/(self.gamma-1) + rho/2*(u**2+v**2)
+
+ from hedge.tools import join_fields
+ return join_fields(rho, e, rho*u, rho*v)
+
+ def volume_interpolant(self, t, discr):
+ return discr.convert_volume(
+ self(t, discr.nodes.T
+ .astype(discr.default_scalar_type)),
+ kind=discr.compute_kind)
+
+ def boundary_interpolant(self, t, discr, tag):
+ return discr.convert_boundary(
+ self(t, discr.get_boundary(tag).nodes.T
+ .astype(discr.default_scalar_type)),
+ tag=tag, kind=discr.compute_kind)
+
+
+
+
diff --git a/examples/gas_dynamics/lbm-simple.py b/examples/gas_dynamics/lbm-simple.py
new file mode 100644
index 0000000000000000000000000000000000000000..4e5cf034f52ff294010fb17087a2d4a47b231d4b
--- /dev/null
+++ b/examples/gas_dynamics/lbm-simple.py
@@ -0,0 +1,153 @@
+# Hedge - the Hybrid'n'Easy DG Environment
+# Copyright (C) 2011 Andreas Kloeckner
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+
+
+
+from __future__ import division
+import numpy as np
+import numpy.linalg as la
+
+
+
+
+def main(write_output=True, dtype=np.float32):
+ from hedge.backends import guess_run_context
+ rcon = guess_run_context()
+
+ from hedge.mesh.generator import make_rect_mesh
+ if rcon.is_head_rank:
+ h_fac = 1
+ mesh = make_rect_mesh(a=(0,0),b=(1,1), max_area=h_fac**2*1e-4,
+ periodicity=(True,True),
+ subdivisions=(int(70/h_fac), int(70/h_fac)))
+
+ from hedge.models.gas_dynamics.lbm import \
+ D2Q9LBMMethod, LatticeBoltzmannOperator
+
+ op = LatticeBoltzmannOperator(
+ D2Q9LBMMethod(), lbm_delta_t=0.001, nu=1e-4)
+
+ if rcon.is_head_rank:
+ print "%d elements" % len(mesh.elements)
+ mesh_data = rcon.distribute_mesh(mesh)
+ else:
+ mesh_data = rcon.receive_mesh()
+
+ discr = rcon.make_discretization(mesh_data, order=3,
+ default_scalar_type=dtype,
+ debug=["cuda_no_plan"])
+ from hedge.timestep.runge_kutta import LSRK4TimeStepper
+ stepper = LSRK4TimeStepper(dtype=dtype,
+ #vector_primitive_factory=discr.get_vector_primitive_factory()
+ )
+
+ from hedge.visualization import VtkVisualizer
+ if write_output:
+ vis = VtkVisualizer(discr, rcon, "fld")
+
+ from hedge.data import CompiledExpressionData
+ def ic_expr(t, x, fields):
+ from hedge.optemplate import CFunction
+ from pymbolic.primitives import IfPositive
+ from pytools.obj_array import make_obj_array
+
+ tanh = CFunction("tanh")
+ sin = CFunction("sin")
+
+ rho = 1
+ u0 = 0.05
+ w = 0.05
+ delta = 0.05
+
+ from hedge.optemplate.primitives import make_common_subexpression as cse
+ u = cse(make_obj_array([
+ IfPositive(x[1]-1/2,
+ u0*tanh(4*(3/4-x[1])/w),
+ u0*tanh(4*(x[1]-1/4)/w)),
+ u0*delta*sin(2*np.pi*(x[0]+1/4))]),
+ "u")
+
+ return make_obj_array([
+ op.method.f_equilibrium(rho, alpha, u)
+ for alpha in range(len(op.method))
+ ])
+
+
+ # timestep loop -----------------------------------------------------------
+ stream_rhs = op.bind_rhs(discr)
+ collision_update = op.bind(discr, op.collision_update)
+ get_rho = op.bind(discr, op.rho)
+ get_rho_u = op.bind(discr, op.rho_u)
+
+
+ f_bar = CompiledExpressionData(ic_expr).volume_interpolant(0, discr)
+
+ from hedge.discretization import ExponentialFilterResponseFunction
+ from hedge.optemplate.operators import FilterOperator
+ mode_filter = FilterOperator(
+ ExponentialFilterResponseFunction(min_amplification=0.9, order=4))\
+ .bind(discr)
+
+ final_time = 1000
+ try:
+ lbm_dt = op.lbm_delta_t
+ dg_dt = op.estimate_timestep(discr, stepper=stepper)
+ print dg_dt
+
+ dg_steps_per_lbm_step = int(np.ceil(lbm_dt / dg_dt))
+ dg_dt = lbm_dt / dg_steps_per_lbm_step
+
+ lbm_steps = int(final_time // op.lbm_delta_t)
+ for step in xrange(lbm_steps):
+ t = step*lbm_dt
+
+ if step % 100 == 0 and write_output:
+ visf = vis.make_file("fld-%04d" % step)
+
+ rho = get_rho(f_bar)
+ rho_u = get_rho_u(f_bar)
+ vis.add_data(visf,
+ [ ("fbar%d" %i,
+ discr.convert_volume(f_bar_i, "numpy")) for i, f_bar_i in enumerate(f_bar)]+
+ [
+ ("rho", discr.convert_volume(rho, "numpy")),
+ ("rho_u", discr.convert_volume(rho_u, "numpy")),
+ ],
+ time=t,
+ step=step)
+ visf.close()
+
+ print "step=%d, t=%f" % (step, t)
+
+ f_bar = collision_update(f_bar)
+
+ for substep in range(dg_steps_per_lbm_step):
+ f_bar = stepper(f_bar, t + substep*dg_dt, dg_dt, stream_rhs)
+
+ #f_bar = mode_filter(f_bar)
+
+ finally:
+ if write_output:
+ vis.close()
+
+ discr.close()
+
+
+
+
+if __name__ == "__main__":
+ main(True)
diff --git a/examples/gas_dynamics/naca.py b/examples/gas_dynamics/naca.py
new file mode 100644
index 0000000000000000000000000000000000000000..9439deeea01fb5b93d5137ddbd4555a3fce3cbe5
--- /dev/null
+++ b/examples/gas_dynamics/naca.py
@@ -0,0 +1,268 @@
+# Hedge - the Hybrid'n'Easy DG Environment
+# Copyright (C) 2008 Andreas Kloeckner
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+
+
+
+from __future__ import division
+import numpy
+import numpy.linalg as la
+
+
+
+
+def make_nacamesh():
+ def round_trip_connect(seq):
+ result = []
+ for i in range(len(seq)):
+ result.append((i, (i+1)%len(seq)))
+ return result
+
+ pt_back = numpy.array([1,0])
+
+ #def max_area(pt):
+ #max_area_front = 1e-2*la.norm(pt)**2 + 1e-5
+ #max_area_back = 1e-2*la.norm(pt-pt_back)**2 + 1e-4
+ #return min(max_area_front, max_area_back)
+
+ def max_area(pt):
+ x = pt[0]
+
+ if x < 0:
+ return 1e-2*la.norm(pt)**2 + 1e-5
+ elif x > 1:
+ return 1e-2*la.norm(pt-pt_back)**2 + 1e-5
+ else:
+ return 1e-2*pt[1]**2 + 1e-5
+
+ def needs_refinement(vertices, area):
+ barycenter = sum(numpy.array(v) for v in vertices)/3
+ return bool(area > max_area(barycenter))
+
+ from meshpy.naca import get_naca_points
+ points = get_naca_points(naca_digits="2412", number_of_points=80)
+
+ from meshpy.geometry import GeometryBuilder, Marker
+ from meshpy.triangle import write_gnuplot_mesh
+
+ profile_marker = Marker.FIRST_USER_MARKER
+ builder = GeometryBuilder()
+ builder.add_geometry(points=points,
+ facets=round_trip_connect(points),
+ facet_markers=profile_marker)
+ builder.wrap_in_box(4, (10, 8))
+
+ from meshpy.triangle import MeshInfo, build
+ mi = MeshInfo()
+ builder.set(mi)
+ mi.set_holes([builder.center()])
+
+ mesh = build(mi, refinement_func=needs_refinement,
+ #allow_boundary_steiner=False,
+ generate_faces=True)
+
+ write_gnuplot_mesh("mesh.dat", mesh)
+
+ print "%d elements" % len(mesh.elements)
+
+ fvi2fm = mesh.face_vertex_indices_to_face_marker
+
+ face_marker_to_tag = {
+ profile_marker: "noslip",
+ Marker.MINUS_X: "inflow",
+ Marker.PLUS_X: "outflow",
+ Marker.MINUS_Y: "inflow",
+ Marker.PLUS_Y: "inflow"
+ #Marker.MINUS_Y: "minus_y",
+ #Marker.PLUS_Y: "plus_y"
+ }
+
+ def bdry_tagger(fvi, el, fn, all_v):
+ face_marker = fvi2fm[fvi]
+ return [face_marker_to_tag[face_marker]]
+
+ from hedge.mesh import make_conformal_mesh_ext
+
+ vertices = numpy.asarray(mesh.points, order="C")
+ from hedge.mesh.element import Triangle
+ return make_conformal_mesh_ext(
+ vertices,
+ [Triangle(i, el_idx, vertices)
+ for i, el_idx in enumerate(mesh.elements)],
+ bdry_tagger,
+ #periodicity=[None, ("minus_y", "plus_y")]
+ )
+
+
+
+
+def main():
+ from hedge.backends import guess_run_context
+ rcon = guess_run_context()
+
+ if rcon.is_head_rank:
+ mesh = make_nacamesh()
+ mesh_data = rcon.distribute_mesh(mesh)
+ else:
+ mesh_data = rcon.receive_mesh()
+
+ from pytools import add_python_path_relative_to_script
+ add_python_path_relative_to_script("..")
+
+ for order in [4]:
+ from gas_dynamics_initials import UniformMachFlow
+ uniform_flow = UniformMachFlow()
+
+ from hedge.models.gas_dynamics import GasDynamicsOperator, GammaLawEOS
+ op = GasDynamicsOperator(dimensions=2,
+ equation_of_state=GammaLawEOS(uniform_flow.gamma),
+ prandtl=uniform_flow.prandtl,
+ spec_gas_const=uniform_flow.spec_gas_const, mu=uniform_flow.mu,
+ bc_inflow=uniform_flow, bc_outflow=uniform_flow, bc_noslip=uniform_flow,
+ inflow_tag="inflow", outflow_tag="outflow", noslip_tag="noslip")
+
+ discr = rcon.make_discretization(mesh_data, order=order,
+ debug=[
+ "cuda_no_plan",
+ #"cuda_dump_kernels",
+ #"dump_optemplate_stages",
+ #"dump_dataflow_graph",
+ #"print_op_code"
+ ],
+ default_scalar_type=numpy.float32,
+ tune_for=op.op_template())
+
+ from hedge.visualization import SiloVisualizer, VtkVisualizer
+ #vis = VtkVisualizer(discr, rcon, "shearflow-%d" % order)
+ vis = SiloVisualizer(discr, rcon)
+
+ fields = uniform_flow.volume_interpolant(0, discr)
+
+ navierstokes_ex = op.bind(discr)
+
+ max_eigval = [0]
+ def rhs(t, q):
+ ode_rhs, speed = navierstokes_ex(t, q)
+ max_eigval[0] = speed
+ return ode_rhs
+ rhs(0, fields)
+
+ if rcon.is_head_rank:
+ print "---------------------------------------------"
+ print "order %d" % order
+ print "---------------------------------------------"
+ print "#elements=", len(mesh.elements)
+
+ from hedge.timestep.runge_kutta import \
+ ODE23TimeStepper, LSRK4TimeStepper
+ stepper = ODE23TimeStepper(dtype=discr.default_scalar_type,
+ rtol=1e-6,
+ vector_primitive_factory=discr.get_vector_primitive_factory())
+ #stepper = LSRK4TimeStepper(dtype=discr.default_scalar_type)
+
+ # diagnostics setup ---------------------------------------------------
+ from pytools.log import LogManager, add_general_quantities, \
+ add_simulation_quantities, add_run_info
+
+ logmgr = LogManager("cns-naca-%d.dat" % order, "w", rcon.communicator)
+
+ add_run_info(logmgr)
+ add_general_quantities(logmgr)
+ add_simulation_quantities(logmgr)
+ discr.add_instrumentation(logmgr)
+ stepper.add_instrumentation(logmgr)
+
+ from pytools.log import LogQuantity
+ class ChangeSinceLastStep(LogQuantity):
+ """Records the change of a variable between a time step and the previous
+ one"""
+
+ def __init__(self, name="change"):
+ LogQuantity.__init__(self, name, "1", "Change since last time step")
+
+ self.old_fields = 0
+
+ def __call__(self):
+ result = discr.norm(fields - self.old_fields)
+ self.old_fields = fields
+ return result
+
+ #logmgr.add_quantity(ChangeSinceLastStep())
+
+ # filter setup-------------------------------------------------------------
+ from hedge.discretization import Filter, ExponentialFilterResponseFunction
+ mode_filter = Filter(discr,
+ ExponentialFilterResponseFunction(min_amplification=0.9,order=4))
+ # timestep loop -------------------------------------------------------
+
+ logmgr.add_watches(["step.max", "t_sim.max", "t_step.max"])
+
+ try:
+ from hedge.timestep import times_and_steps
+ step_it = times_and_steps(
+ final_time=200,
+ #max_steps=500,
+ logmgr=logmgr,
+ max_dt_getter=lambda t: next_dt,
+ taken_dt_getter=lambda: taken_dt)
+
+ model_stepper = LSRK4TimeStepper()
+ next_dt = op.estimate_timestep(discr,
+ stepper=model_stepper, t=0,
+ max_eigenvalue=max_eigval[0])
+
+ for step, t, dt in step_it:
+ if step % 10 == 0:
+ visf = vis.make_file("naca-%d-%06d" % (order, step))
+
+ from pyvisfile.silo import DB_VARTYPE_VECTOR
+ vis.add_data(visf,
+ [
+ ("rho", discr.convert_volume(op.rho(fields), kind="numpy")),
+ ("e", discr.convert_volume(op.e(fields), kind="numpy")),
+ ("rho_u", discr.convert_volume(op.rho_u(fields), kind="numpy")),
+ ("u", discr.convert_volume(op.u(fields), kind="numpy")),
+
+ #("true_rho", op.rho(true_fields)),
+ #("true_e", op.e(true_fields)),
+ #("true_rho_u", op.rho_u(true_fields)),
+ #("true_u", op.u(true_fields)),
+
+ #("rhs_rho", discr.convert_volume(op.rho(rhs_fields), kind="numpy")),
+ #("rhs_e", discr.convert_volume(op.e(rhs_fields), kind="numpy")),
+ #("rhs_rho_u", discr.convert_volume(op.rho_u(rhs_fields), kind="numpy")),
+ ],
+ expressions=[
+ #("diff_rho", "rho-true_rho"),
+ #("diff_e", "e-true_e"),
+ #("diff_rho_u", "rho_u-true_rho_u", DB_VARTYPE_VECTOR),
+
+ ("p", "(0.4)*(e- 0.5*(rho_u*u))"),
+ ],
+ time=t, step=step
+ )
+ visf.close()
+
+ fields, t, taken_dt, next_dt = stepper(fields, t, dt, rhs)
+ fields = mode_filter(fields)
+
+ finally:
+ vis.close()
+ logmgr.save()
+ discr.close()
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/gas_dynamics/navierstokes/shearflow.py b/examples/gas_dynamics/navierstokes/shearflow.py
new file mode 100644
index 0000000000000000000000000000000000000000..597c2b0b8d7862e11f723134a60d2f76e43eb58c
--- /dev/null
+++ b/examples/gas_dynamics/navierstokes/shearflow.py
@@ -0,0 +1,198 @@
+# Hedge - the Hybrid'n'Easy DG Environment
+# Copyright (C) 2008 Andreas Kloeckner
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+
+
+
+from __future__ import division
+import numpy
+import numpy.linalg as la
+
+
+
+
+class SteadyShearFlow:
+ def __init__(self):
+ self.gamma = 1.5
+ self.mu = 0.01
+ self.prandtl = 0.72
+ self.spec_gas_const = 287.1
+
+ def __call__(self, t, x_vec):
+ # JSH/TW Nodal DG Methods, p.326
+
+ rho = numpy.ones_like(x_vec[0])
+ rho_u = x_vec[1] * x_vec[1]
+ rho_v = numpy.zeros_like(x_vec[0])
+ e = (2 * self.mu * x_vec[0] + 10) / (self.gamma - 1) + x_vec[1]**4 / 2
+
+ from hedge.tools import join_fields
+ return join_fields(rho, e, rho_u, rho_v)
+
+ def properties(self):
+ return(self.gamma, self.mu, self.prandtl, self.spec_gas_const)
+
+ def volume_interpolant(self, t, discr):
+ return discr.convert_volume(
+ self(t, discr.nodes.T
+ .astype(discr.default_scalar_type)),
+ kind=discr.compute_kind)
+
+ def boundary_interpolant(self, t, discr, tag):
+ result = discr.convert_boundary(
+ self(t, discr.get_boundary(tag).nodes.T
+ .astype(discr.default_scalar_type)),
+ tag=tag, kind=discr.compute_kind)
+ return result
+
+
+
+
+def main():
+ from hedge.backends import guess_run_context
+ rcon = guess_run_context(
+ #["cuda"]
+ )
+
+ from hedge.tools import EOCRecorder, to_obj_array
+ eoc_rec = EOCRecorder()
+
+ def boundary_tagger(vertices, el, face_nr, all_v):
+ return ["inflow"]
+
+ if rcon.is_head_rank:
+ from hedge.mesh import make_rect_mesh, \
+ make_centered_regular_rect_mesh
+ #mesh = make_rect_mesh((0,0), (10,1), max_area=0.01)
+ refine = 1
+ mesh = make_centered_regular_rect_mesh((0,0), (10,1), n=(20,4),
+ #periodicity=(True, False),
+ post_refine_factor=refine,
+ boundary_tagger=boundary_tagger)
+ mesh_data = rcon.distribute_mesh(mesh)
+ else:
+ mesh_data = rcon.receive_mesh()
+
+ for order in [3]:
+ discr = rcon.make_discretization(mesh_data, order=order,
+ default_scalar_type=numpy.float64)
+
+ from hedge.visualization import SiloVisualizer, VtkVisualizer
+ #vis = VtkVisualizer(discr, rcon, "shearflow-%d" % order)
+ vis = SiloVisualizer(discr, rcon)
+
+ shearflow = SteadyShearFlow()
+ fields = shearflow.volume_interpolant(0, discr)
+ gamma, mu, prandtl, spec_gas_const = shearflow.properties()
+
+ from hedge.models.gas_dynamics import GasDynamicsOperator
+ op = GasDynamicsOperator(dimensions=2, gamma=gamma, mu=mu,
+ prandtl=prandtl, spec_gas_const=spec_gas_const,
+ bc_inflow=shearflow, bc_outflow=shearflow, bc_noslip=shearflow,
+ inflow_tag="inflow", outflow_tag="outflow", noslip_tag="noslip")
+
+ navierstokes_ex = op.bind(discr)
+
+ max_eigval = [0]
+ def rhs(t, q):
+ ode_rhs, speed = navierstokes_ex(t, q)
+ max_eigval[0] = speed
+ return ode_rhs
+
+ # needed to get first estimate of maximum eigenvalue
+ rhs(0, fields)
+
+ if rcon.is_head_rank:
+ print "---------------------------------------------"
+ print "order %d" % order
+ print "---------------------------------------------"
+ print "#elements=", len(mesh.elements)
+
+ from hedge.timestep import RK4TimeStepper
+ stepper = RK4TimeStepper()
+
+ # diagnostics setup ---------------------------------------------------
+ from pytools.log import LogManager, add_general_quantities, \
+ add_simulation_quantities, add_run_info
+
+ logmgr = LogManager("navierstokes-cpu-%d-%d.dat" % (order, refine),
+ "w", rcon.communicator)
+ add_run_info(logmgr)
+ add_general_quantities(logmgr)
+ add_simulation_quantities(logmgr)
+ discr.add_instrumentation(logmgr)
+ stepper.add_instrumentation(logmgr)
+
+ logmgr.add_watches(["step.max", "t_sim.max", "t_step.max"])
+
+ # timestep loop -------------------------------------------------------
+ try:
+ from hedge.timestep import times_and_steps
+ step_it = times_and_steps(
+ final_time=0.3,
+ #max_steps=500,
+ logmgr=logmgr,
+ max_dt_getter=lambda t: op.estimate_timestep(discr,
+ stepper=stepper, t=t, max_eigenvalue=max_eigval[0]))
+
+ for step, t, dt in step_it:
+ if step % 10 == 0:
+ #if False:
+ visf = vis.make_file("shearflow-%d-%04d" % (order, step))
+
+ #true_fields = shearflow.volume_interpolant(t, discr)
+
+ from pyvisfile.silo import DB_VARTYPE_VECTOR
+ vis.add_data(visf,
+ [
+ ("rho", discr.convert_volume(op.rho(fields), kind="numpy")),
+ ("e", discr.convert_volume(op.e(fields), kind="numpy")),
+ ("rho_u", discr.convert_volume(op.rho_u(fields), kind="numpy")),
+ ("u", discr.convert_volume(op.u(fields), kind="numpy")),
+
+ #("true_rho", discr.convert_volume(op.rho(true_fields), kind="numpy")),
+ #("true_e", discr.convert_volume(op.e(true_fields), kind="numpy")),
+ #("true_rho_u", discr.convert_volume(op.rho_u(true_fields), kind="numpy")),
+ #("true_u", discr.convert_volume(op.u(true_fields), kind="numpy")),
+ ],
+ expressions=[
+ #("diff_rho", "rho-true_rho"),
+ #("diff_e", "e-true_e"),
+ #("diff_rho_u", "rho_u-true_rho_u", DB_VARTYPE_VECTOR),
+
+ ("p", "0.4*(e- 0.5*(rho_u*u))"),
+ ],
+ time=t, step=step
+ )
+ visf.close()
+
+ fields = stepper(fields, t, dt, rhs)
+
+ true_fields = shearflow.volume_interpolant(t, discr)
+ l2_error = discr.norm(op.u(fields)-op.u(true_fields))
+ eoc_rec.add_data_point(order, l2_error)
+ print
+ print eoc_rec.pretty_print("P.Deg.", "L2 Error")
+
+ logmgr.set_constant("l2_error", l2_error)
+
+ finally:
+ vis.close()
+ logmgr.save()
+ discr.close()
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/gas_dynamics/square.py b/examples/gas_dynamics/square.py
new file mode 100644
index 0000000000000000000000000000000000000000..f1e63e62445a2e735af4eece1859d83bdc2b7231
--- /dev/null
+++ b/examples/gas_dynamics/square.py
@@ -0,0 +1,281 @@
+# Hedge - the Hybrid'n'Easy DG Environment
+# Copyright (C) 2008 Andreas Kloeckner
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+
+
+
+from __future__ import division
+import numpy
+import numpy.linalg as la
+
+
+
+
+def make_squaremesh():
+ def round_trip_connect(seq):
+ result = []
+ for i in range(len(seq)):
+ result.append((i, (i+1)%len(seq)))
+ return result
+
+ def needs_refinement(vertices, area):
+ x = sum(numpy.array(v) for v in vertices)/3
+
+ max_area_volume = 0.7e-2 + 0.03*(0.05*x[1]**2 + 0.3*min(x[0]+1,0)**2)
+
+ max_area_corners = 1e-3 + 0.001*max(
+ la.norm(x-corner)**4 for corner in obstacle_corners)
+
+ return bool(area > 2.5*min(max_area_volume, max_area_corners))
+
+ from meshpy.geometry import make_box
+ points, facets, _, _ = make_box((-0.5,-0.5), (0.5,0.5))
+ obstacle_corners = points[:]
+
+ from meshpy.geometry import GeometryBuilder, Marker
+
+ profile_marker = Marker.FIRST_USER_MARKER
+ builder = GeometryBuilder()
+ builder.add_geometry(points=points, facets=facets,
+ facet_markers=profile_marker)
+
+ points, facets, _, facet_markers = make_box((-16, -22), (25, 22))
+ builder.add_geometry(points=points, facets=facets,
+ facet_markers=facet_markers)
+
+ from meshpy.triangle import MeshInfo, build
+ mi = MeshInfo()
+ builder.set(mi)
+ mi.set_holes([(0,0)])
+
+ mesh = build(mi, refinement_func=needs_refinement,
+ allow_boundary_steiner=True,
+ generate_faces=True)
+
+ print "%d elements" % len(mesh.elements)
+
+ from meshpy.triangle import write_gnuplot_mesh
+ write_gnuplot_mesh("mesh.dat", mesh)
+
+ fvi2fm = mesh.face_vertex_indices_to_face_marker
+
+ face_marker_to_tag = {
+ profile_marker: "noslip",
+ Marker.MINUS_X: "inflow",
+ Marker.PLUS_X: "outflow",
+ Marker.MINUS_Y: "inflow",
+ Marker.PLUS_Y: "inflow"
+ }
+
+ def bdry_tagger(fvi, el, fn, all_v):
+ face_marker = fvi2fm[fvi]
+ return [face_marker_to_tag[face_marker]]
+
+ from hedge.mesh import make_conformal_mesh_ext
+ vertices = numpy.asarray(mesh.points, dtype=float, order="C")
+ from hedge.mesh.element import Triangle
+ return make_conformal_mesh_ext(
+ vertices,
+ [Triangle(i, el_idx, vertices)
+ for i, el_idx in enumerate(mesh.elements)],
+ bdry_tagger)
+
+
+
+
+def main():
+ import logging
+ logging.basicConfig(level=logging.INFO)
+
+ from hedge.backends import guess_run_context
+ rcon = guess_run_context()
+
+ if rcon.is_head_rank:
+ if True:
+ mesh = make_squaremesh()
+ else:
+ from hedge.mesh import make_rect_mesh
+ mesh = make_rect_mesh(
+ boundary_tagger=lambda fvi, el, fn, all_v: ["inflow"],
+ max_area=0.1)
+
+ mesh_data = rcon.distribute_mesh(mesh)
+ else:
+ mesh_data = rcon.receive_mesh()
+
+ from pytools import add_python_path_relative_to_script
+ add_python_path_relative_to_script(".")
+
+ for order in [3]:
+ from gas_dynamics_initials import UniformMachFlow
+ square = UniformMachFlow(gaussian_pulse_at=numpy.array([-2, 2]),
+ pulse_magnitude=0.003)
+
+ from hedge.models.gas_dynamics import (
+ GasDynamicsOperator,
+ GammaLawEOS)
+
+ op = GasDynamicsOperator(dimensions=2,
+ equation_of_state=GammaLawEOS(square.gamma), mu=square.mu,
+ prandtl=square.prandtl, spec_gas_const=square.spec_gas_const,
+ bc_inflow=square, bc_outflow=square, bc_noslip=square,
+ inflow_tag="inflow", outflow_tag="outflow", noslip_tag="noslip")
+
+ discr = rcon.make_discretization(mesh_data, order=order,
+ debug=["cuda_no_plan",
+ "cuda_dump_kernels",
+ #"dump_dataflow_graph",
+ #"dump_optemplate_stages",
+ #"dump_dataflow_graph",
+ #"dump_op_code"
+ #"cuda_no_plan_el_local"
+ ],
+ default_scalar_type=numpy.float64,
+ tune_for=op.op_template(),
+ quad_min_degrees={
+ "gasdyn_vol": 3*order,
+ "gasdyn_face": 3*order,
+ }
+ )
+
+ from hedge.visualization import SiloVisualizer, VtkVisualizer
+ #vis = VtkVisualizer(discr, rcon, "shearflow-%d" % order)
+ vis = SiloVisualizer(discr, rcon)
+
+ from hedge.timestep.runge_kutta import (
+ LSRK4TimeStepper, ODE23TimeStepper, ODE45TimeStepper)
+ from hedge.timestep.dumka3 import Dumka3TimeStepper
+ #stepper = LSRK4TimeStepper(dtype=discr.default_scalar_type,
+ #vector_primitive_factory=discr.get_vector_primitive_factory())
+
+ stepper = ODE23TimeStepper(dtype=discr.default_scalar_type,
+ rtol=1e-6,
+ vector_primitive_factory=discr.get_vector_primitive_factory())
+ # Dumka works kind of poorly
+ #stepper = Dumka3TimeStepper(dtype=discr.default_scalar_type,
+ #rtol=1e-7, pol_index=2,
+ #vector_primitive_factory=discr.get_vector_primitive_factory())
+
+ #from hedge.timestep.dumka3 import Dumka3TimeStepper
+ #stepper = Dumka3TimeStepper(3, rtol=1e-7)
+
+ # diagnostics setup ---------------------------------------------------
+ from pytools.log import LogManager, add_general_quantities, \
+ add_simulation_quantities, add_run_info
+
+ logmgr = LogManager("cns-square-sp-%d.dat" % order, "w", rcon.communicator)
+
+ add_run_info(logmgr)
+ add_general_quantities(logmgr)
+ discr.add_instrumentation(logmgr)
+ stepper.add_instrumentation(logmgr)
+
+ from pytools.log import LogQuantity
+ class ChangeSinceLastStep(LogQuantity):
+ """Records the change of a variable between a time step and the previous
+ one"""
+
+ def __init__(self, name="change"):
+ LogQuantity.__init__(self, name, "1", "Change since last time step")
+
+ self.old_fields = 0
+
+ def __call__(self):
+ result = discr.norm(fields - self.old_fields)
+ self.old_fields = fields
+ return result
+
+ #logmgr.add_quantity(ChangeSinceLastStep())
+
+ add_simulation_quantities(logmgr)
+ logmgr.add_watches(["step.max", "t_sim.max", "t_step.max"])
+
+ # filter setup ------------------------------------------------------------
+ from hedge.discretization import Filter, ExponentialFilterResponseFunction
+ mode_filter = Filter(discr,
+ ExponentialFilterResponseFunction(min_amplification=0.95, order=6))
+
+ # timestep loop -------------------------------------------------------
+ fields = square.volume_interpolant(0, discr)
+
+ navierstokes_ex = op.bind(discr)
+
+ max_eigval = [0]
+ def rhs(t, q):
+ ode_rhs, speed = navierstokes_ex(t, q)
+ max_eigval[0] = speed
+ return ode_rhs
+ rhs(0, fields)
+
+ if rcon.is_head_rank:
+ print "---------------------------------------------"
+ print "order %d" % order
+ print "---------------------------------------------"
+ print "#elements=", len(mesh.elements)
+
+ try:
+ from hedge.timestep import times_and_steps
+ step_it = times_and_steps(
+ final_time=1000,
+ #max_steps=500,
+ logmgr=logmgr,
+ max_dt_getter=lambda t: next_dt,
+ taken_dt_getter=lambda: taken_dt)
+
+ model_stepper = LSRK4TimeStepper()
+ next_dt = op.estimate_timestep(discr,
+ stepper=model_stepper, t=0,
+ max_eigenvalue=max_eigval[0])
+
+ for step, t, dt in step_it:
+ #if (step % 10000 == 0): #and step < 950000) or (step % 500 == 0 and step > 950000):
+ #if False:
+ if step % 5 == 0:
+ visf = vis.make_file("square-%d-%06d" % (order, step))
+
+ #from pyvisfile.silo import DB_VARTYPE_VECTOR
+ vis.add_data(visf,
+ [
+ ("rho", discr.convert_volume(op.rho(fields), kind="numpy")),
+ ("e", discr.convert_volume(op.e(fields), kind="numpy")),
+ ("rho_u", discr.convert_volume(op.rho_u(fields), kind="numpy")),
+ ("u", discr.convert_volume(op.u(fields), kind="numpy")),
+ ],
+ expressions=[
+ ("p", "(0.4)*(e- 0.5*(rho_u*u))"),
+ ],
+ time=t, step=step
+ )
+ visf.close()
+
+ if stepper.adaptive:
+ fields, t, taken_dt, next_dt = stepper(fields, t, dt, rhs)
+ else:
+ taken_dt = dt
+ fields = stepper(fields, t, dt, rhs)
+ dt = op.estimate_timestep(discr,
+ stepper=model_stepper, t=0,
+ max_eigenvalue=max_eigval[0])
+
+ #fields = mode_filter(fields)
+
+ finally:
+ vis.close()
+ logmgr.save()
+ discr.close()
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/gas_dynamics/wing.py b/examples/gas_dynamics/wing.py
new file mode 100644
index 0000000000000000000000000000000000000000..de8243249729281d783b8fb9b9b771d879543cc5
--- /dev/null
+++ b/examples/gas_dynamics/wing.py
@@ -0,0 +1,232 @@
+# Hedge - the Hybrid'n'Easy DG Environment
+# Copyright (C) 2008 Andreas Kloeckner
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+
+
+
+from __future__ import division
+import numpy
+import numpy.linalg as la
+
+
+
+
+def make_wingmesh():
+ import numpy
+ from math import pi, cos, sin
+ from meshpy.tet import MeshInfo, build
+ from meshpy.geometry import GeometryBuilder, Marker, \
+ generate_extrusion, make_box
+
+ geob = GeometryBuilder()
+
+ profile_marker = Marker.FIRST_USER_MARKER
+
+ wing_length = 2
+ wing_subdiv = 5
+
+ rz_points = [
+ (0, -wing_length*1.05),
+ (0.7, -wing_length*1.05),
+ ] + [
+ (r, x) for x, r in zip(
+ numpy.linspace(-wing_length, 0, wing_subdiv, endpoint=False),
+ numpy.linspace(0.8, 1, wing_subdiv, endpoint=False))
+ ] + [(1,0)] + [
+ (r, x) for x, r in zip(
+ numpy.linspace(wing_length, 0, wing_subdiv, endpoint=False),
+ numpy.linspace(0.8, 1, wing_subdiv, endpoint=False))
+ ][::-1] + [
+ (0.7, wing_length*1.05),
+ (0, wing_length*1.05)
+ ]
+
+ from meshpy.naca import get_naca_points
+ geob.add_geometry(*generate_extrusion(
+ rz_points=rz_points,
+ base_shape=get_naca_points("0012", number_of_points=20),
+ ring_markers=(wing_subdiv*2+4)*[profile_marker]))
+
+ def deform_wing(p):
+ x, y, z = p
+ return numpy.array([
+ x + 0.8*abs(z/wing_length)** 1.2,
+ y + 0.1*abs(z/wing_length)**2,
+ z])
+
+ geob.apply_transform(deform_wing)
+
+ points, facets, facet_markers = make_box(
+ numpy.array([-1.5,-1,-wing_length-1], dtype=numpy.float64),
+ numpy.array([3,1,wing_length+1], dtype=numpy.float64))
+
+ geob.add_geometry(points, facets, facet_markers=facet_markers)
+
+ mesh_info = MeshInfo()
+ geob.set(mesh_info)
+ mesh_info.set_holes([(0.5,0,0)])
+
+ mesh = build(mesh_info)
+ print "%d elements" % len(mesh.elements)
+
+ fvi2fm = mesh.face_vertex_indices_to_face_marker
+
+ face_marker_to_tag = {
+ profile_marker: "noslip",
+ Marker.MINUS_X: "inflow",
+ Marker.PLUS_X: "outflow",
+ Marker.MINUS_Y: "inflow",
+ Marker.PLUS_Y: "inflow",
+ Marker.PLUS_Z: "inflow",
+ Marker.MINUS_Z: "inflow"
+ }
+
+ def bdry_tagger(fvi, el, fn, all_v):
+ face_marker = fvi2fm[fvi]
+ return [face_marker_to_tag[face_marker]]
+
+ from hedge.mesh import make_conformal_mesh
+ return make_conformal_mesh(mesh.points, mesh.elements, bdry_tagger)
+
+
+
+
+def main():
+ from hedge.backends import guess_run_context
+ rcon = guess_run_context( ["cuda", "mpi"])
+
+ if rcon.is_head_rank:
+ mesh = make_wingmesh()
+ #from hedge.mesh import make_rect_mesh
+ #mesh = make_rect_mesh(
+ # boundary_tagger=lambda fvi, el, fn, all_v: ["inflow"])
+ mesh_data = rcon.distribute_mesh(mesh)
+ else:
+ mesh_data = rcon.receive_mesh()
+
+ for order in [3]:
+ from pytools import add_python_path_relative_to_script
+ add_python_path_relative_to_script("..")
+
+ from gas_dynamics_initials import UniformMachFlow
+ wing = UniformMachFlow(angle_of_attack=0)
+
+ from hedge.models.gas_dynamics import GasDynamicsOperator
+ op = GasDynamicsOperator(dimensions=3,
+ gamma=wing.gamma, mu=wing.mu,
+ prandtl=wing.prandtl, spec_gas_const=wing.spec_gas_const,
+ bc_inflow=wing, bc_outflow=wing, bc_noslip=wing,
+ inflow_tag="inflow", outflow_tag="outflow", noslip_tag="noslip")
+
+ discr = rcon.make_discretization(mesh_data, order=order,
+ debug=["cuda_no_plan",
+ #"cuda_dump_kernels",
+ #"dump_dataflow_graph",
+ #"dump_optemplate_stages",
+ #"dump_dataflow_graph",
+ #"print_op_code"
+ "cuda_no_metis",
+ ],
+ default_scalar_type=numpy.float64,
+ tune_for=op.op_template())
+
+ from hedge.visualization import SiloVisualizer, VtkVisualizer
+ #vis = VtkVisualizer(discr, rcon, "shearflow-%d" % order)
+ vis = SiloVisualizer(discr, rcon)
+
+ fields = wing.volume_interpolant(0, discr)
+
+ navierstokes_ex = op.bind(discr)
+
+ max_eigval = [0]
+ def rhs(t, q):
+ ode_rhs, speed = navierstokes_ex(t, q)
+ max_eigval[0] = speed
+ return ode_rhs
+ rhs(0, fields)
+
+ if rcon.is_head_rank:
+ print "---------------------------------------------"
+ print "order %d" % order
+ print "---------------------------------------------"
+ print "#elements=", len(mesh.elements)
+
+ from hedge.timestep import RK4TimeStepper
+ stepper = RK4TimeStepper()
+
+ # diagnostics setup ---------------------------------------------------
+ from pytools.log import LogManager, add_general_quantities, \
+ add_simulation_quantities, add_run_info
+
+ logmgr = LogManager("navierstokes-%d.dat" % order, "w", rcon.communicator)
+ add_run_info(logmgr)
+ add_general_quantities(logmgr)
+ add_simulation_quantities(logmgr)
+ discr.add_instrumentation(logmgr)
+ stepper.add_instrumentation(logmgr)
+
+ logmgr.add_watches(["step.max", "t_sim.max", "t_step.max"])
+
+ # timestep loop -------------------------------------------------------
+ try:
+ from hedge.timestep import times_and_steps
+ step_it = times_and_steps(
+ final_time=200,
+ #max_steps=500,
+ logmgr=logmgr,
+ max_dt_getter=lambda t: 0.6 * op.estimate_timestep(discr,
+ stepper=stepper, t=t, max_eigenvalue=max_eigval[0]))
+
+ for step, t, dt in step_it:
+ if step % 200 == 0:
+ #if False:
+ visf = vis.make_file("wing-%d-%06d" % (order, step))
+
+ #rhs_fields = rhs(t, fields)
+
+ from pyvisfile.silo import DB_VARTYPE_VECTOR
+ from hedge.discretization import ones_on_boundary
+ vis.add_data(visf,
+ [
+ ("rho", discr.convert_volume(op.rho(fields), kind="numpy")),
+ ("e", discr.convert_volume(op.e(fields), kind="numpy")),
+ ("rho_u", discr.convert_volume(op.rho_u(fields), kind="numpy")),
+ ("u", discr.convert_volume(op.u(fields), kind="numpy")),
+
+ #("rhs_rho", discr.convert_volume(op.rho(rhs_fields), kind="numpy")),
+ #("rhs_e", discr.convert_volume(op.e(rhs_fields), kind="numpy")),
+ #("rhs_rho_u", discr.convert_volume(op.rho_u(rhs_fields), kind="numpy")),
+ ],
+ expressions=[
+ ("p", "(0.4)*(e- 0.5*(rho_u*u))"),
+ ],
+ time=t, step=step
+ )
+ visf.close()
+
+ fields = stepper(fields, t, dt, rhs)
+ t += dt
+
+ finally:
+ vis.close()
+ logmgr.save()
+ discr.close()
+
+
+
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/heat/heat.py b/examples/heat/heat.py
new file mode 100644
index 0000000000000000000000000000000000000000..6cd193f72077f417e9f4ee250412d28d761a2478
--- /dev/null
+++ b/examples/heat/heat.py
@@ -0,0 +1,174 @@
+# Hedge - the Hybrid'n'Easy DG Environment
+# Copyright (C) 2007 Andreas Kloeckner
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+
+
+
+import numpy
+import numpy.linalg as la
+
+
+
+
+def main(write_output=True) :
+ from math import sin, cos, pi, exp, sqrt
+ from hedge.data import TimeConstantGivenFunction, \
+ ConstantGivenFunction
+
+ from hedge.backends import guess_run_context
+ rcon = guess_run_context()
+
+ dim = 2
+
+ def boundary_tagger(fvi, el, fn, all_v):
+ if el.face_normals[fn][0] > 0:
+ return ["dirichlet"]
+ else:
+ return ["neumann"]
+
+ if dim == 2:
+ if rcon.is_head_rank:
+ from hedge.mesh.generator import make_disk_mesh
+ mesh = make_disk_mesh(r=0.5, boundary_tagger=boundary_tagger)
+ elif dim == 3:
+ if rcon.is_head_rank:
+ from hedge.mesh.generator import make_ball_mesh
+ mesh = make_ball_mesh(max_volume=0.001)
+ else:
+ raise RuntimeError, "bad number of dimensions"
+
+ if rcon.is_head_rank:
+ print "%d elements" % len(mesh.elements)
+ mesh_data = rcon.distribute_mesh(mesh)
+ else:
+ mesh_data = rcon.receive_mesh()
+
+ discr = rcon.make_discretization(mesh_data, order=3,
+ debug=["cuda_no_plan"],
+ default_scalar_type=numpy.float64)
+
+ if write_output:
+ from hedge.visualization import VtkVisualizer
+ vis = VtkVisualizer(discr, rcon, "fld")
+
+ def u0(x, el):
+ if la.norm(x) < 0.2:
+ return 1
+ else:
+ return 0
+
+ def coeff(x, el):
+ if x[0] < 0:
+ return 0.25
+ else:
+ return 1
+
+ def dirichlet_bc(t, x):
+ return 0
+
+ def neumann_bc(t, x):
+ return 2
+
+ from hedge.models.diffusion import DiffusionOperator
+ op = DiffusionOperator(discr.dimensions,
+ #coeff=coeff,
+ dirichlet_tag="dirichlet",
+ dirichlet_bc=TimeConstantGivenFunction(ConstantGivenFunction(0)),
+ neumann_tag="neumann",
+ neumann_bc=TimeConstantGivenFunction(ConstantGivenFunction(1))
+ )
+ u = discr.interpolate_volume_function(u0)
+
+ # diagnostics setup -------------------------------------------------------
+ from pytools.log import LogManager, \
+ add_general_quantities, \
+ add_simulation_quantities, \
+ add_run_info
+
+ if write_output:
+ log_file_name = "heat.dat"
+ else:
+ log_file_name = None
+
+ logmgr = LogManager(log_file_name, "w", rcon.communicator)
+ add_run_info(logmgr)
+ add_general_quantities(logmgr)
+ add_simulation_quantities(logmgr)
+ discr.add_instrumentation(logmgr)
+
+ from hedge.log import LpNorm
+ u_getter = lambda: u
+ logmgr.add_quantity(LpNorm(u_getter, discr, 1, name="l1_u"))
+ logmgr.add_quantity(LpNorm(u_getter, discr, name="l2_u"))
+
+ logmgr.add_watches(["step.max", "t_sim.max", "l2_u", "t_step.max"])
+
+ # timestep loop -----------------------------------------------------------
+ from hedge.timestep.runge_kutta import LSRK4TimeStepper, ODE45TimeStepper
+ from hedge.timestep.dumka3 import Dumka3TimeStepper
+ #stepper = LSRK4TimeStepper()
+ stepper = Dumka3TimeStepper(3, rtol=1e-6, rcon=rcon,
+ vector_primitive_factory=discr.get_vector_primitive_factory(),
+ dtype=discr.default_scalar_type)
+ #stepper = ODE45TimeStepper(rtol=1e-6, rcon=rcon,
+ #vector_primitive_factory=discr.get_vector_primitive_factory(),
+ #dtype=discr.default_scalar_type)
+ stepper.add_instrumentation(logmgr)
+
+ rhs = op.bind(discr)
+ try:
+ next_dt = op.estimate_timestep(discr,
+ stepper=LSRK4TimeStepper(), t=0, fields=u)
+
+ from hedge.timestep import times_and_steps
+ step_it = times_and_steps(
+ final_time=0.1, logmgr=logmgr,
+ max_dt_getter=lambda t: next_dt,
+ taken_dt_getter=lambda: taken_dt)
+
+ for step, t, dt in step_it:
+ if step % 10 == 0 and write_output:
+ visf = vis.make_file("fld-%04d" % step)
+ vis.add_data(visf, [
+ ("u", discr.convert_volume(u, kind="numpy")),
+ ], time=t, step=step)
+ visf.close()
+
+ u, t, taken_dt, next_dt = stepper(u, t, next_dt, rhs)
+ #u = stepper(u, t, dt, rhs)
+
+ assert discr.norm(u) < 1
+ finally:
+ if write_output:
+ vis.close()
+
+ logmgr.close()
+ discr.close()
+
+
+
+
+if __name__ == "__main__":
+ main()
+
+
+
+
+# entry points for py.test ----------------------------------------------------
+from pytools.test import mark_test
+@mark_test.long
+def test_heat():
+ main(write_output=False)
diff --git a/examples/maxwell/.gitignore b/examples/maxwell/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..641163859ce66ad7bebf63db3035f0d58abef797
--- /dev/null
+++ b/examples/maxwell/.gitignore
@@ -0,0 +1,2 @@
+bessel_zeros.py
+2d_cavity
diff --git a/examples/maxwell/analytic_solutions.py b/examples/maxwell/analytic_solutions.py
new file mode 100644
index 0000000000000000000000000000000000000000..64505c949f500177ce91203426cd75a479f27dad
--- /dev/null
+++ b/examples/maxwell/analytic_solutions.py
@@ -0,0 +1,457 @@
+# Hedge - the Hybrid'n'Easy DG Environment
+# Copyright (C) 2007 Andreas Kloeckner
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+
+
+
+from __future__ import division
+from hedge.tools import \
+ cyl_bessel_j, \
+ cyl_bessel_j_prime
+from math import sqrt, pi, sin, cos, atan2, acos
+import numpy
+import numpy.linalg as la
+import cmath
+
+
+
+
+# solution adapters -----------------------------------------------------------
+class RealPartAdapter:
+ def __init__(self, adaptee):
+ self.adaptee = adaptee
+
+ @property
+ def shape(self):
+ return self.adaptee.shape
+
+ def __call__(self, x, el):
+ return [xi.real for xi in self.adaptee(x, el)]
+
+class SplitComplexAdapter:
+ def __init__(self, adaptee):
+ self.adaptee = adaptee
+
+ @property
+ def shape(self):
+ (n,) = self.adaptee.shape
+ return (n*2,)
+
+ def __call__(self, x, el):
+ ad_x = self.adaptee(x, el)
+ return [xi.real for xi in ad_x] + [xi.imag for xi in ad_x]
+
+
+
+
+class CylindricalFieldAdapter:
+ """Turns a field returned as (r, phi, z) components into
+ (x,y,z) components.
+ """
+ def __init__(self, adaptee):
+ self.adaptee = adaptee
+
+ @property
+ def shape(self):
+ return self.adaptee.shape
+
+ def __call__(self, x, el):
+ xy = x[:2]
+ r = la.norm(xy)
+ phi = atan2(x[1], x[0])
+
+ prev_result = self.adaptee(x, el)
+ result = []
+ i = 0
+ while i < len(prev_result):
+ fr, fphi, fz = prev_result[i:i+3]
+ result.extend([
+ cos(phi)*fr - sin(phi)*fphi, # ex
+ sin(phi)*fr + cos(phi)*fphi, # ey
+ fz,
+ ])
+ i += 3
+
+ return result
+
+
+
+
+class SphericalFieldAdapter:
+ """Turns the adaptee's field C{(Er, Etheta, Ephi)} components into
+ C{(Ex,Ey,Ez)} components.
+
+ Conventions are those of
+ http://mathworld.wolfram.com/SphericalCoordinates.html
+ """
+ def __init__(self, adaptee):
+ self.adaptee = adaptee
+
+ @property
+ def shape(self):
+ return self.adaptee.shape
+
+ @staticmethod
+ def r_theta_phi_from_xyz(x):
+ r = la.norm(x)
+ return r, atan2(x[1], x[0]), acos(x[2]/r)
+
+ def __call__(self, x, el):
+ r, theta, phi = self.r_theta_phi_from_xyz(x)
+
+ er = numpy.array([
+ cos(theta)*sin(phi),
+ sin(theta)*sin(phi),
+ cos(phi)])
+ etheta = numpy.array([
+ -sin(theta),
+ cos(theta),
+ 0])
+ ephi = numpy.array([
+ cos(theta)*cos(phi),
+ sin(theta)*cos(phi),
+ -sin(phi)])
+
+ adaptee_result = self.adaptee(x, el)
+ result = numpy.empty_like(adaptee_result)
+ i = 0
+ while i < len(adaptee_result):
+ fr, ftheta, fphi = adaptee_result[i:i+3]
+ result[i:i+3] = fr*er + ftheta*etheta + fphi*ephi
+ i += 3
+
+ return result
+
+
+
+
+# actual solutions ------------------------------------------------------------
+class CylindricalCavityMode:
+ """A cylindrical TM cavity mode.
+
+ Taken from:
+ J.D. Jackson, Classical Electrodynamics, Wiley.
+ 3rd edition, 2001.
+ ch 8.7, p. 368f.
+ """
+
+ def __init__(self, m, n, p, radius, height, epsilon, mu):
+ try:
+ from bessel_zeros import bessel_zeros
+ except ImportError:
+ print "*** You need to generate the bessel root data file."
+ print "*** Execute generate-bessel-zeros.py at the command line."
+ raise
+
+ assert m >= 0 and m == int(m)
+ assert n >= 1 and n == int(n)
+ assert p >= 0 and p == int(p)
+ self.m = m
+ self.n = n
+ self.p = p
+ self.phi_sign = 1
+
+ R = self.radius = radius
+ d = self.height = height
+
+ self.epsilon = epsilon
+ self.mu = mu
+
+ self.t = 0
+
+ x_mn = bessel_zeros[m][n-1]
+
+ self.omega = 1 / sqrt(mu*epsilon) * sqrt(
+ x_mn**2 / R**2
+ + p**2 * pi**2 / d**2)
+
+ self.gamma_mn = x_mn/R
+
+ def set_time(self, t):
+ self.t = t
+
+ shape = (6,)
+
+ def __call__(self, x, el):
+ # coordinates -----------------------------------------------------
+ xy = x[:2]
+ r = sqrt(xy*xy)
+ phi = atan2(x[1], x[0])
+ z = x[2]
+
+ # copy instance variables for easier access -----------------------
+ m = self.m
+ p = self.p
+ gamma = self.gamma_mn
+ phi_sign = self.phi_sign
+ omega = self.omega
+ d = self.height
+ epsilon = self.epsilon
+
+ # common subexpressions -------------------------------------------
+ tdep = cmath.exp(-1j * omega * self.t)
+ phi_factor = cmath.exp(phi_sign * 1j * m * phi)
+
+ # psi and derivatives ---------------------------------------------
+ psi = cyl_bessel_j(m, gamma * r) * phi_factor
+ psi_dr = gamma*cyl_bessel_j_prime(m, gamma*r) * phi_factor
+ psi_dphi = (cyl_bessel_j(m, gamma * r)
+ * 1/r * phi_sign*1j*m * phi_factor)
+
+ # field components in polar coordinates ---------------------------
+ ez = tdep * cos(p * pi * z / d) * psi
+
+ e_transverse_factor = (tdep
+ * (-p*pi/(d*gamma**2))
+ * sin(p * pi * z / d))
+
+ er = e_transverse_factor * psi_dr
+ ephi = e_transverse_factor * psi_dphi
+
+ hz = 0j
+
+ # z x grad psi = z x (psi_x, psi_y) = (-psi_y, psi_x)
+ # z x grad psi = z x (psi_r, psi_phi) = (-psi_phi, psi_r)
+ h_transverse_factor = (tdep
+ * 1j*epsilon*omega/gamma**2
+ * cos(p * pi * z / d))
+
+ hr = h_transverse_factor * (-psi_dphi)
+ hphi = h_transverse_factor * psi_dr
+
+ return [er, ephi, ez, hr, hphi, hz]
+
+
+
+
+class RectangularWaveguideMode:
+ """A rectangular TM cavity mode."""
+
+ def __init__(self, epsilon, mu, mode_indices,
+ dimensions=(1,1,1), coefficients=(1,0,0),
+ forward_coeff=1, backward_coeff=0):
+ for n in mode_indices:
+ assert n >= 0 and n == int(n)
+ self.mode_indices = mode_indices
+ self.dimensions = dimensions
+ self.coefficients = coefficients
+ self.forward_coeff = forward_coeff
+ self.backward_coeff = backward_coeff
+
+ self.epsilon = epsilon
+ self.mu = mu
+
+ self.t = 0
+
+ self.factors = [n*pi/a for n, a in zip(self.mode_indices, self.dimensions)]
+
+ c = 1/sqrt(mu*epsilon)
+ self.k = sqrt(sum(f**2 for f in self.factors))
+ self.omega = self.k*c
+
+ def set_time(self, t):
+ self.t = t
+
+ def __call__(self, discr):
+ f,g,h = self.factors
+ omega = self.omega
+ k = self.k
+
+ x = discr.nodes[:,0]
+ y = discr.nodes[:,1]
+ if discr.dimensions > 2:
+ z = discr.nodes[:,2]
+ else:
+ z = discr.volume_zeros()
+
+ sx = numpy.sin(f*x)
+ sy = numpy.sin(g*y)
+ cx = numpy.cos(f*x)
+ cy = numpy.cos(g*y)
+
+ zdep_add = numpy.exp(1j*h*z)+numpy.exp(-1j*h*z)
+ zdep_sub = numpy.exp(1j*h*z)-numpy.exp(-1j*h*z)
+
+ tdep = numpy.exp(-1j * omega * self.t)
+
+ C = 1j/(f**2+g**2)
+
+ result = numpy.zeros((6,len(x)), dtype=zdep_add.dtype)
+
+ result[0] = C*f*h*cx*sy*zdep_sub*tdep # ex
+ result[1] = C*g*h*sx*cy*zdep_sub*tdep # ey
+ result[2] = sx*sy*zdep_add*tdep # ez
+ result[3] = -C*g*self.epsilon*omega*sx*cy*zdep_add*tdep # hx
+ result[4] = C*f*self.epsilon*omega*cx*sy*zdep_add*tdep
+
+ return result
+
+
+
+
+class RectangularCavityMode(RectangularWaveguideMode):
+ """A rectangular TM cavity mode."""
+
+ def __init__(self, *args, **kwargs):
+ if "scale" in kwargs:
+ kwargs["forward_coeff"] = scale
+ kwargs["backward_coeff"] = scale
+ else:
+ kwargs["forward_coeff"] = 1
+ kwargs["backward_coeff"] = 1
+ RectangularWaveguideMode.__init__(self, *args, **kwargs)
+
+
+
+
+
+# dipole solution -------------------------------------------------------------
+class DipoleFarField:
+ """Dipole EM field.
+
+ See U{http://piki.tiker.net/wiki/Dipole}.
+ """
+ def __init__(self, q, d, omega, epsilon, mu):
+ self.q = q
+ self.d = d
+
+ self.epsilon = epsilon
+ self.mu = mu
+ self.c = c = 1/sqrt(mu*epsilon)
+
+ self.omega = omega
+
+ freq = omega/(2*pi)
+ self.wavelength = c/freq
+
+ def far_field_mask(self, x, el):
+ if la.norm(x) > 0.5*self.wavelength:
+ return 1
+ else:
+ return 0
+
+ def set_time(self, t):
+ self.t = t
+
+ shape = (6,)
+
+ def __call__(self, x, el):
+ # coordinates ---------------------------------------------------------
+ r, theta, phi = SphericalFieldAdapter.r_theta_phi_from_xyz(x)
+
+ # copy instance variables for easier access ---------------------------
+ q = self.q
+ d = self.d
+
+ epsilon = self.epsilon
+ mu = self.mu
+ c = self.c
+
+ omega = self.omega
+ t = self.t
+
+ # field components ----------------------------------------------------
+ tdep = omega*t-omega*r/c
+ e_r = (2*cos(phi)*q*d) / (4*pi*epsilon) * (
+ 1/r**3 * sin(tdep)
+ +omega/(c*r**2) * cos(tdep))
+ e_phi = (sin(phi)*q*d) / (4*pi*epsilon) * (
+ (1/r**3 - omega**2/(c**2*r)*sin(tdep))
+ + omega/(c*r**2)*cos(tdep))
+ h_theta = (omega*sin(phi)*q*d)/(4*pi) * (
+ - omega/(c*r)*sin(tdep)
+ + 1/r**2*cos(tdep))
+
+ return [e_r, 0, e_phi, 0, h_theta, 0]
+
+ def source_modulation(self, t):
+ j0 = self.q*self.d*self.omega/self.epsilon
+ return j0*cos(self.omega*t)
+
+
+
+
+# analytic solution tools -----------------------------------------------------
+def check_time_harmonic_solution(discr, mode, c_sol):
+ from hedge.discretization import bind_nabla, bind_mass_matrix
+ from hedge.visualization import SiloVisualizer
+ from hedge.silo import SiloFile
+ from hedge.tools import dot, cross
+ from hedge.silo import DB_VARTYPE_VECTOR
+
+ def curl(field):
+ return cross(nabla, field)
+
+ vis = SiloVisualizer(discr)
+
+ nabla = bind_nabla(discr)
+ mass = bind_mass_matrix(discr)
+
+ def rel_l2_error(err, base):
+ def l2_norm(field):
+ return sqrt(dot(field, mass*field))
+
+ base_l2 = l2_norm(base)
+ err_l2 = l2_norm(err)
+ if base_l2 == 0:
+ if err_l2 == 0:
+ return 0.
+ else:
+ return float("inf")
+ else:
+ return err_l2/base_l2
+
+ dt = 0.1
+
+ for step in range(10):
+ t = step*dt
+ mode.set_time(t)
+ fields = discr.interpolate_volume_function(c_sol)
+
+ er = fields[0:3]
+ hr = fields[3:6]
+ ei = fields[6:9]
+ hi = fields[9:12]
+
+ silo = SiloFile("em-complex-%04d.silo" % step)
+ vis.add_to_silo(silo,
+ vectors=[
+ ("curl_er", curl(er)),
+ ("om_hi", -mode.mu*mode.omega*hi),
+ ("curl_hr", curl(hr)),
+ ("om_ei", mode.epsilon*mode.omega*hi),
+ ],
+ expressions=[
+ ("diff_er", "curl_er-om_hi", DB_VARTYPE_VECTOR),
+ ("diff_hr", "curl_hr-om_ei", DB_VARTYPE_VECTOR),
+ ],
+ write_coarse_mesh=True,
+ time=t, step=step
+ )
+
+ er_res = curl(er) + mode.mu *mode.omega*hi
+ ei_res = curl(ei) - mode.mu *mode.omega*hr
+ hr_res = curl(hr) - mode.epsilon*mode.omega*ei
+ hi_res = curl(hi) + mode.epsilon*mode.omega*er
+
+ print "time=%f, rel l2 residual in Re[E]=%g\tIm[E]=%g\tRe[H]=%g\tIm[H]=%g" % (
+ t,
+ rel_l2_error(er_res, er),
+ rel_l2_error(ei_res, ei),
+ rel_l2_error(hr_res, hr),
+ rel_l2_error(hi_res, hi),
+ )
+
diff --git a/examples/maxwell/cavities.py b/examples/maxwell/cavities.py
new file mode 100644
index 0000000000000000000000000000000000000000..b1e2dfea38d85140176f484a684f492d8d91512f
--- /dev/null
+++ b/examples/maxwell/cavities.py
@@ -0,0 +1,259 @@
+# Hedge - the Hybrid'n'Easy DG Environment
+# Copyright (C) 2007 Andreas Kloeckner
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+
+from __future__ import division
+import numpy as np
+
+import logging
+logger = logging.getLogger(__name__)
+
+
+def main(write_output=True, allow_features=None, flux_type_arg=1,
+ bdry_flux_type_arg=None, extra_discr_args={}):
+ from hedge.mesh.generator import make_cylinder_mesh, make_box_mesh
+ from hedge.tools import EOCRecorder, to_obj_array
+ from math import sqrt, pi # noqa
+ from analytic_solutions import ( # noqa
+ RealPartAdapter,
+ SplitComplexAdapter,
+ CylindricalFieldAdapter,
+ CylindricalCavityMode,
+ RectangularWaveguideMode,
+ RectangularCavityMode)
+ from hedge.models.em import MaxwellOperator
+
+ logging.basicConfig(level=logging.DEBUG)
+
+ from hedge.backends import guess_run_context
+ rcon = guess_run_context(allow_features)
+
+ epsilon0 = 8.8541878176e-12 # C**2 / (N m**2)
+ mu0 = 4*pi*1e-7 # N/A**2.
+ epsilon = 1*epsilon0
+ mu = 1*mu0
+
+ eoc_rec = EOCRecorder()
+
+ cylindrical = False
+ periodic = False
+
+ if cylindrical:
+ R = 1
+ d = 2
+ mode = CylindricalCavityMode(m=1, n=1, p=1,
+ radius=R, height=d,
+ epsilon=epsilon, mu=mu)
+ # r_sol = CylindricalFieldAdapter(RealPartAdapter(mode))
+ # c_sol = SplitComplexAdapter(CylindricalFieldAdapter(mode))
+
+ if rcon.is_head_rank:
+ mesh = make_cylinder_mesh(radius=R, height=d, max_volume=0.01)
+ else:
+ if periodic:
+ mode = RectangularWaveguideMode(epsilon, mu, (3, 2, 1))
+ periodicity = (False, False, True)
+ else:
+ periodicity = None
+ mode = RectangularCavityMode(epsilon, mu, (1, 2, 2))
+
+ if rcon.is_head_rank:
+ mesh = make_box_mesh(max_volume=0.001, periodicity=periodicity)
+
+ if rcon.is_head_rank:
+ mesh_data = rcon.distribute_mesh(mesh)
+ else:
+ mesh_data = rcon.receive_mesh()
+
+ for order in [4, 5, 6]:
+ #for order in [1,2,3,4,5,6]:
+ extra_discr_args.setdefault("debug", []).extend([
+ "cuda_no_plan", "cuda_dump_kernels"])
+
+ op = MaxwellOperator(epsilon, mu,
+ flux_type=flux_type_arg,
+ bdry_flux_type=bdry_flux_type_arg)
+
+ discr = rcon.make_discretization(mesh_data, order=order,
+ tune_for=op.op_template(),
+ **extra_discr_args)
+
+ from hedge.visualization import VtkVisualizer
+ if write_output:
+ vis = VtkVisualizer(discr, rcon, "em-%d" % order)
+
+ mode.set_time(0)
+
+ def get_true_field():
+ return discr.convert_volume(
+ to_obj_array(mode(discr)
+ .real.astype(discr.default_scalar_type).copy()),
+ kind=discr.compute_kind)
+
+ fields = get_true_field()
+
+ if rcon.is_head_rank:
+ print "---------------------------------------------"
+ print "order %d" % order
+ print "---------------------------------------------"
+ print "#elements=", len(mesh.elements)
+
+ from hedge.timestep.runge_kutta import LSRK4TimeStepper
+ stepper = LSRK4TimeStepper(dtype=discr.default_scalar_type, rcon=rcon)
+ #from hedge.timestep.dumka3 import Dumka3TimeStepper
+ #stepper = Dumka3TimeStepper(3, dtype=discr.default_scalar_type, rcon=rcon)
+
+ # {{{ diagnostics setup
+
+ from pytools.log import LogManager, add_general_quantities, \
+ add_simulation_quantities, add_run_info
+
+ if write_output:
+ log_file_name = "maxwell-%d.dat" % order
+ else:
+ log_file_name = None
+
+ logmgr = LogManager(log_file_name, "w", rcon.communicator)
+
+ add_run_info(logmgr)
+ add_general_quantities(logmgr)
+ add_simulation_quantities(logmgr)
+ discr.add_instrumentation(logmgr)
+ stepper.add_instrumentation(logmgr)
+
+ from pytools.log import IntervalTimer
+ vis_timer = IntervalTimer("t_vis", "Time spent visualizing")
+ logmgr.add_quantity(vis_timer)
+
+ from hedge.log import EMFieldGetter, add_em_quantities
+ field_getter = EMFieldGetter(discr, op, lambda: fields)
+ add_em_quantities(logmgr, op, field_getter)
+
+ logmgr.add_watches(
+ ["step.max", "t_sim.max",
+ ("W_field", "W_el+W_mag"),
+ "t_step.max"]
+ )
+
+ # }}}
+
+ # {{{ timestep loop
+
+ rhs = op.bind(discr)
+ final_time = 0.5e-9
+
+ try:
+ from hedge.timestep import times_and_steps
+ step_it = times_and_steps(
+ final_time=final_time, logmgr=logmgr,
+ max_dt_getter=lambda t: op.estimate_timestep(discr,
+ stepper=stepper, t=t, fields=fields))
+
+ for step, t, dt in step_it:
+ if step % 50 == 0 and write_output:
+ sub_timer = vis_timer.start_sub_timer()
+ e, h = op.split_eh(fields)
+ visf = vis.make_file("em-%d-%04d" % (order, step))
+ vis.add_data(
+ visf,
+ [
+ ("e",
+ discr.convert_volume(e, kind="numpy")),
+ ("h",
+ discr.convert_volume(h, kind="numpy")),
+ ],
+ time=t, step=step)
+ visf.close()
+ sub_timer.stop().submit()
+
+ fields = stepper(fields, t, dt, rhs)
+
+ mode.set_time(final_time)
+
+ eoc_rec.add_data_point(order,
+ discr.norm(fields-get_true_field()))
+
+ finally:
+ if write_output:
+ vis.close()
+
+ logmgr.close()
+ discr.close()
+
+ if rcon.is_head_rank:
+ print
+ print eoc_rec.pretty_print("P.Deg.", "L2 Error")
+
+ # }}}
+
+ assert eoc_rec.estimate_order_of_convergence()[0, 1] > 6
+
+
+# {{{ entry points for py.test
+
+from pytools.test import mark_test
+
+
+@mark_test.long
+def test_maxwell_cavities():
+ main(write_output=False)
+
+
+@mark_test.long
+def test_maxwell_cavities_lf():
+ main(write_output=False, flux_type_arg="lf", bdry_flux_type_arg=1)
+
+
+@mark_test.mpi
+@mark_test.long
+def test_maxwell_cavities_mpi():
+ from pytools.mpi import run_with_mpi_ranks
+ run_with_mpi_ranks(__file__, 2, main,
+ write_output=False, allow_features=["mpi"])
+
+
+def test_cuda():
+ try:
+ from pycuda.tools import mark_cuda_test
+ except ImportError:
+ pass
+
+ yield "SP CUDA Maxwell", mark_cuda_test(
+ do_test_maxwell_cavities_cuda), np.float32
+ yield "DP CUDA Maxwell", mark_cuda_test(
+ do_test_maxwell_cavities_cuda), np.float64
+
+
+def do_test_maxwell_cavities_cuda(dtype):
+ import pytest # noqa
+
+ main(write_output=False, allow_features=["cuda"],
+ extra_discr_args=dict(
+ debug=["cuda_no_plan"],
+ default_scalar_type=dtype,
+ ))
+
+# }}}
+
+
+# entry point -----------------------------------------------------------------
+
+if __name__ == "__main__":
+ from pytools.mpi import in_mpi_relaunch
+ if in_mpi_relaunch():
+ test_maxwell_cavities_mpi()
+ else:
+ do_test_maxwell_cavities_cuda(np.float32)
diff --git a/examples/maxwell/dipole.py b/examples/maxwell/dipole.py
new file mode 100644
index 0000000000000000000000000000000000000000..261434c1f020f06448dd0042c4adf1b280c944e2
--- /dev/null
+++ b/examples/maxwell/dipole.py
@@ -0,0 +1,257 @@
+# Hedge - the Hybrid'n'Easy DG Environment
+# Copyright (C) 2007 Andreas Kloeckner
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+# FIXME: This example doesn't quite do what it should any more.
+
+
+
+
+from __future__ import division
+import numpy
+import numpy.linalg as la
+
+
+
+
+def main(write_output=True, allow_features=None):
+ from hedge.timestep import RK4TimeStepper
+ from hedge.mesh import make_ball_mesh, make_cylinder_mesh, make_box_mesh
+ from hedge.visualization import \
+ VtkVisualizer, \
+ SiloVisualizer, \
+ get_rank_partition
+ from math import sqrt, pi
+
+ from hedge.backends import guess_run_context
+ rcon = guess_run_context(allow_features)
+
+ epsilon0 = 8.8541878176e-12 # C**2 / (N m**2)
+ mu0 = 4*pi*1e-7 # N/A**2.
+ epsilon = 1*epsilon0
+ mu = 1*mu0
+
+ dims = 3
+
+ if rcon.is_head_rank:
+ if dims == 2:
+ from hedge.mesh import make_rect_mesh
+ mesh = make_rect_mesh(
+ a=(-10.5,-1.5),
+ b=(10.5,1.5),
+ max_area=0.1
+ )
+ elif dims == 3:
+ from hedge.mesh import make_box_mesh
+ mesh = make_box_mesh(
+ a=(-10.5,-1.5,-1.5),
+ b=(10.5,1.5,1.5),
+ max_volume=0.1)
+
+ if rcon.is_head_rank:
+ mesh_data = rcon.distribute_mesh(mesh)
+ else:
+ mesh_data = rcon.receive_mesh()
+
+ #for order in [1,2,3,4,5,6]:
+ discr = rcon.make_discretization(mesh_data, order=3)
+
+ if write_output:
+ vis = VtkVisualizer(discr, rcon, "dipole")
+
+ from analytic_solutions import DipoleFarField, SphericalFieldAdapter
+ from hedge.data import ITimeDependentGivenFunction
+
+ sph_dipole = DipoleFarField(
+ q=1, #C
+ d=1/39,
+ omega=2*pi*1e8,
+ epsilon=epsilon0,
+ mu=mu0,
+ )
+ cart_dipole = SphericalFieldAdapter(sph_dipole)
+
+ class PointDipoleSource(ITimeDependentGivenFunction):
+ def __init__(self):
+ from pyrticle.tools import CInfinityShapeFunction
+ sf = CInfinityShapeFunction(
+ 0.1*sph_dipole.wavelength,
+ discr.dimensions)
+ self.num_sf = discr.interpolate_volume_function(
+ lambda x, el: sf(x))
+ self.vol_0 = discr.volume_zeros()
+
+ def volume_interpolant(self, t, discr):
+ from hedge.tools import make_obj_array
+ return make_obj_array([
+ self.vol_0,
+ self.vol_0,
+ sph_dipole.source_modulation(t)*self.num_sf
+ ])
+
+ from hedge.mesh import TAG_ALL, TAG_NONE
+ if dims == 2:
+ from hedge.models.em import TMMaxwellOperator as MaxwellOperator
+ else:
+ from hedge.models.em import MaxwellOperator
+
+ op = MaxwellOperator(
+ epsilon, mu,
+ flux_type=1,
+ pec_tag=TAG_NONE,
+ absorb_tag=TAG_ALL,
+ current=PointDipoleSource(),
+ )
+
+ fields = op.assemble_eh(discr=discr)
+
+ if rcon.is_head_rank:
+ print "#elements=", len(mesh.elements)
+
+ stepper = RK4TimeStepper()
+
+ # diagnostics setup ---------------------------------------------------
+ from pytools.log import LogManager, add_general_quantities, \
+ add_simulation_quantities, add_run_info
+
+ if write_output:
+ log_file_name = "dipole.dat"
+ else:
+ log_file_name = None
+
+ logmgr = LogManager(log_file_name, "w", rcon.communicator)
+ add_run_info(logmgr)
+ add_general_quantities(logmgr)
+ add_simulation_quantities(logmgr)
+ discr.add_instrumentation(logmgr)
+ stepper.add_instrumentation(logmgr)
+
+ from pytools.log import IntervalTimer
+ vis_timer = IntervalTimer("t_vis", "Time spent visualizing")
+ logmgr.add_quantity(vis_timer)
+
+ from hedge.log import EMFieldGetter, add_em_quantities
+ field_getter = EMFieldGetter(discr, op, lambda: fields)
+ add_em_quantities(logmgr, op, field_getter)
+
+ from pytools.log import PushLogQuantity
+ relerr_e_q = PushLogQuantity("relerr_e", "1", "Relative error in masked E-field")
+ relerr_h_q = PushLogQuantity("relerr_h", "1", "Relative error in masked H-field")
+ logmgr.add_quantity(relerr_e_q)
+ logmgr.add_quantity(relerr_h_q)
+
+ logmgr.add_watches(["step.max", "t_sim.max",
+ ("W_field", "W_el+W_mag"), "t_step.max",
+ "relerr_e", "relerr_h"])
+
+ if write_output:
+ point_timeseries = [
+ (open("b-x%d-vs-time.dat" % i, "w"),
+ open("b-x%d-vs-time-true.dat" % i, "w"),
+ discr.get_point_evaluator(numpy.array([i,0,0][:dims],
+ dtype=discr.default_scalar_type)))
+ for i in range(1,5)
+ ]
+
+ # timestep loop -------------------------------------------------------
+ mask = discr.interpolate_volume_function(sph_dipole.far_field_mask)
+
+ def apply_mask(field):
+ from hedge.tools import log_shape
+ ls = log_shape(field)
+ result = discr.volume_empty(ls)
+ from pytools import indices_in_shape
+ for i in indices_in_shape(ls):
+ result[i] = mask * field[i]
+
+ return result
+
+ rhs = op.bind(discr)
+
+ t = 0
+ try:
+ from hedge.timestep import times_and_steps
+ step_it = times_and_steps(
+ final_time=1e-8, logmgr=logmgr,
+ max_dt_getter=lambda t: op.estimate_timestep(discr,
+ stepper=stepper, t=t, fields=fields))
+
+ for step, t, dt in step_it:
+ if write_output and step % 10 == 0:
+ sub_timer = vis_timer.start_sub_timer()
+ e, h = op.split_eh(fields)
+ sph_dipole.set_time(t)
+ true_e, true_h = op.split_eh(
+ discr.interpolate_volume_function(cart_dipole))
+ visf = vis.make_file("dipole-%04d" % step)
+
+ mask_e = apply_mask(e)
+ mask_h = apply_mask(h)
+ mask_true_e = apply_mask(true_e)
+ mask_true_h = apply_mask(true_h)
+
+ from pyvisfile.silo import DB_VARTYPE_VECTOR
+ vis.add_data(visf,
+ [
+ ("e", e),
+ ("h", h),
+ ("true_e", true_e),
+ ("true_h", true_h),
+ ("mask_e", mask_e),
+ ("mask_h", mask_h),
+ ("mask_true_e", mask_true_e),
+ ("mask_true_h", mask_true_h)],
+ time=t, step=step)
+ visf.close()
+ sub_timer.stop().submit()
+
+ from hedge.tools import relative_error
+ relerr_e_q.push_value(
+ relative_error(
+ discr.norm(mask_e-mask_true_e),
+ discr.norm(mask_true_e)))
+ relerr_h_q.push_value(
+ relative_error(
+ discr.norm(mask_h-mask_true_h),
+ discr.norm(mask_true_h)))
+
+ if write_output:
+ for outf_num, outf_true, evaluator in point_timeseries:
+ for outf, ev_h in zip([outf_num, outf_true],
+ [h, true_h]):
+ outf.write("%g\t%g\n" % (t, op.mu*evaluator(ev_h[1])))
+ outf.flush()
+
+ fields = stepper(fields, t, dt, rhs)
+
+ finally:
+ if write_output:
+ vis.close()
+
+ logmgr.save()
+ discr.close()
+
+
+
+if __name__ == "__main__":
+ main()
+
+
+
+
+from pytools.test import mark_test
+@mark_test.long
+def test_run():
+ main(write_output=False)
diff --git a/examples/maxwell/generate-bessel-zeros.py b/examples/maxwell/generate-bessel-zeros.py
new file mode 100644
index 0000000000000000000000000000000000000000..9c3b11b64baafab78186d4ded0cdaa1589ae579e
--- /dev/null
+++ b/examples/maxwell/generate-bessel-zeros.py
@@ -0,0 +1,14 @@
+def main():
+ import scipy.special
+
+ maxnu = 10
+ n_zeros = 20
+
+ zeros = []
+ for n in range(0,maxnu+1):
+ zeros.append(list(scipy.special.jn_zeros(n, n_zeros)))
+
+ outf = open("bessel_zeros.py", "w").write("bessel_zeros = %s" % zeros)
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/maxwell/inhom-cavity.py b/examples/maxwell/inhom-cavity.py
new file mode 100644
index 0000000000000000000000000000000000000000..70f4a8e434f73aacba6d36ebb29b1c1170aac008
--- /dev/null
+++ b/examples/maxwell/inhom-cavity.py
@@ -0,0 +1,265 @@
+# Hedge - the Hybrid'n'Easy DG Environment
+# Copyright (C) 2007 Andreas Kloeckner
+# Adapted 2010 by David Powell
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+"""This example is for maxwell's equations in a 2D rectangular cavity
+with inhomogeneous dielectric filling"""
+
+from __future__ import division
+import numpy
+
+CAVITY_GEOMETRY = """
+// a rectangular cavity with a dielectric in one region
+
+lc = 10e-3;
+height = 50e-3;
+air_width = 100e-3;
+dielectric_width = 50e-3;
+
+Point(1) = {0, 0, 0, lc};
+Point(2) = {air_width, 0, 0, lc};
+Point(3) = {air_width+dielectric_width, 0, 0, lc};
+Point(4) = {air_width+dielectric_width, height, 0, lc};
+Point(5) = {air_width, height, 0, lc};
+Point(6) = {0, height, 0, lc};
+
+Line(1) = {1, 2};
+Line(2) = {2, 3};
+Line(3) = {3, 4};
+Line(4) = {4, 5};
+Line(5) = {5, 6};
+Line(6) = {6, 1};
+Line(7) = {2, 5};
+
+Line Loop(1) = {1, 7, 5, 6};
+Line Loop(2) = {2, 3, 4, -7};
+
+Plane Surface(1) = {1};
+Plane Surface(2) = {2};
+
+Physical Surface("vacuum") = {1};
+Physical Surface("dielectric") = {2};
+"""
+
+
+def main(write_output=True, allow_features=None, flux_type_arg=1,
+ bdry_flux_type_arg=None, extra_discr_args={}):
+ from math import sqrt, pi
+ from hedge.models.em import TEMaxwellOperator
+
+ from hedge.backends import guess_run_context
+ rcon = guess_run_context(allow_features)
+
+ epsilon0 = 8.8541878176e-12 # C**2 / (N m**2)
+ mu0 = 4*pi*1e-7 # N/A**2.
+ c = 1/sqrt(mu0*epsilon0)
+
+ materials = {"vacuum" : (epsilon0, mu0),
+ "dielectric" : (2*epsilon0, mu0)}
+
+ output_dir = "2d_cavity"
+
+ import os
+ if not os.access(output_dir, os.F_OK):
+ os.makedirs(output_dir)
+
+ # should no tag raise an error or default to free space?
+ def eps_val(x, el):
+ for key in materials.keys():
+ if el in material_elements[key]:
+ return materials[key][0]
+ raise ValueError, "Element does not belong to any material"
+
+ def mu_val(x, el):
+ for key in materials.keys():
+ if el in material_elements[key]:
+ return materials[key][1]
+ raise ValueError, "Element does not belong to any material"
+
+ # geometry of cavity
+ d = 100e-3
+ a = 150e-3
+
+ # analytical frequency and transverse wavenumbers of resonance
+ f0 = 9.0335649907522321e8
+ h = 2*pi*f0/c
+ l = -h*sqrt(2)
+
+ # substitute the following and change materials for a homogeneous cavity
+ #h = pi/a
+ #l =-h
+
+ def initial_val(discr):
+ # the initial solution for the TE_10-like mode
+ def initial_Hz(x, el):
+ from math import cos, sin
+ if el in material_elements["vacuum"]:
+ return h*cos(h*x[0])
+ else:
+ return -l*sin(h*d)/sin(l*(a-d))*cos(l*(a-x[0]))
+
+ from hedge.tools import make_obj_array
+ result_zero = discr.volume_zeros(kind="numpy", dtype=numpy.float64)
+ H_z = make_tdep_given(initial_Hz).volume_interpolant(0, discr)
+ return make_obj_array([result_zero, result_zero, H_z])
+
+ if rcon.is_head_rank:
+ from hedge.mesh.reader.gmsh import generate_gmsh
+ mesh = generate_gmsh(CAVITY_GEOMETRY, 2, force_dimension=2)
+ mesh_data = rcon.distribute_mesh(mesh)
+ else:
+ mesh_data = rcon.receive_mesh()
+
+ # Work out which elements belong to each material
+ material_elements = {}
+ for key in materials.keys():
+ material_elements[key] = set(mesh_data.tag_to_elements[key])
+
+ order = 3
+ #extra_discr_args.setdefault("debug", []).append("cuda_no_plan")
+ #extra_discr_args.setdefault("debug", []).append("dump_optemplate_stages")
+
+ from hedge.data import make_tdep_given
+ from hedge.mesh import TAG_ALL
+
+ op = TEMaxwellOperator(epsilon=make_tdep_given(eps_val), mu=make_tdep_given(mu_val), \
+ flux_type=flux_type_arg, \
+ bdry_flux_type=bdry_flux_type_arg, dimensions=2, pec_tag=TAG_ALL)
+ # op = TEMaxwellOperator(epsilon=epsilon0, mu=mu0,
+ # flux_type=flux_type_arg, \
+ # bdry_flux_type=bdry_flux_type_arg, dimensions=2, pec_tag=TAG_ALL)
+
+ discr = rcon.make_discretization(mesh_data, order=order,
+ tune_for=op.op_template(),
+ **extra_discr_args)
+
+ # create the initial solution
+ fields = initial_val(discr)
+
+ from hedge.visualization import VtkVisualizer
+ if write_output:
+ from os.path import join
+ vis = VtkVisualizer(discr, rcon, join(output_dir, "cav-%d" % order))
+
+ # monitor the solution at a point to find the resonant frequency
+ try:
+ point_getter = discr.get_point_evaluator(numpy.array([75e-3, 25e-3, 0])) #[0.25, 0.25, 0.25]))
+ except RuntimeError:
+ point_getter = None
+
+ if rcon.is_head_rank:
+ print "---------------------------------------------"
+ print "order %d" % order
+ print "---------------------------------------------"
+ print "#elements=", len(mesh.elements)
+
+ from hedge.timestep.runge_kutta import LSRK4TimeStepper
+ stepper = LSRK4TimeStepper(dtype=discr.default_scalar_type, rcon=rcon)
+ #from hedge.timestep.dumka3 import Dumka3TimeStepper
+ #stepper = Dumka3TimeStepper(3, dtype=discr.default_scalar_type, rcon=rcon)
+
+ # diagnostics setup ---------------------------------------------------
+ from pytools.log import LogManager, add_general_quantities, \
+ add_simulation_quantities, add_run_info
+
+ if write_output:
+ from os.path import join
+ log_file_name = join(output_dir, "cavity-%d.dat" % order)
+ else:
+ log_file_name = None
+
+ logmgr = LogManager(log_file_name, "w", rcon.communicator)
+
+ add_run_info(logmgr)
+ add_general_quantities(logmgr)
+ add_simulation_quantities(logmgr)
+ discr.add_instrumentation(logmgr)
+ stepper.add_instrumentation(logmgr)
+
+ from pytools.log import IntervalTimer
+ vis_timer = IntervalTimer("t_vis", "Time spent visualizing")
+ logmgr.add_quantity(vis_timer)
+
+ #from hedge.log import EMFieldGetter, add_em_quantities
+ #field_getter = EMFieldGetter(discr, op, lambda: fields)
+ #add_em_quantities(logmgr, op, field_getter)
+
+ logmgr.add_watches(
+ ["step.max", "t_sim.max",
+ #("W_field", "W_el+W_mag"),
+ "t_step.max"]
+ )
+
+ # timestep loop -------------------------------------------------------
+ rhs = op.bind(discr)
+ final_time = 10e-9
+
+ if point_getter is not None:
+ from os.path import join
+ pointfile = open(join(output_dir, "point.txt"), "wt")
+ done_dt = False
+ try:
+ from hedge.timestep import times_and_steps
+ from os.path import join
+ step_it = times_and_steps(
+ final_time=final_time, logmgr=logmgr,
+ max_dt_getter=lambda t: op.estimate_timestep(discr,
+ stepper=stepper, t=t, fields=fields))
+
+ for step, t, dt in step_it:
+ if step % 10 == 0 and write_output:
+ sub_timer = vis_timer.start_sub_timer()
+ e, h = op.split_eh(fields)
+ visf = vis.make_file(join(output_dir, "cav-%d-%04d") % (order, step))
+ vis.add_data(visf,
+ [
+ ("e",
+ discr.convert_volume(e, kind="numpy")),
+ ("h",
+ discr.convert_volume(h, kind="numpy")),],
+ time=t, step=step
+ )
+ visf.close()
+ sub_timer.stop().submit()
+
+ fields = stepper(fields, t, dt, rhs)
+ if point_getter is not None:
+ val = point_getter(fields)
+ #print val
+ if not done_dt:
+ pointfile.write("#%g\n" % dt)
+ done_dt = True
+ pointfile.write("%g\n" %val[0])
+
+ finally:
+ if write_output:
+ vis.close()
+
+ logmgr.close()
+ discr.close()
+
+ if point_getter is not None:
+ pointfile.close()
+
+
+
+
+
+
+
+# entry point -----------------------------------------------------------------
+if __name__ == "__main__":
+ main(write_output=True)
diff --git a/examples/maxwell/inhomogeneous_waveguide.mac b/examples/maxwell/inhomogeneous_waveguide.mac
new file mode 100644
index 0000000000000000000000000000000000000000..28a582f428be9e3193e4b012f4029d45464f0db9
--- /dev/null
+++ b/examples/maxwell/inhomogeneous_waveguide.mac
@@ -0,0 +1,39 @@
+
+/*
+From Robert E. Collin, Field Theory of Guided Waves, p. 413, chaper 6
+
+Find the cut-off frequency of a rectangular waveguide partially filled with a dielectric slab,
+in order to find the resonant frequency of an inhomogeneous 2D cavity.
+
+Take (5a), the transcendental equation for h and l, and substitute for their definitions in terms of gamma
+Then solve for the condition that gamma is 0, for the mode with m=0.
+t - width of dielectric section
+d - width of air section
+kappa - relative permittivity
+k_0 - free space wavenumber
+gamma - waveguide wavenumber
+l - transverse wavenumber in dielectric
+h - transverse wavenumber in air
+*/
+
+trans_eq : h*tan(l*t) + l*tan(h*d);
+l_gamma : sqrt(gamma^2 - (m*pi/b)^2 + kappa*k_0^2);
+h_gamma : sqrt(gamma^2 - (m*pi/b)^2 + k_0^2);
+l_simp : l_gamma, gamma=0, m=0;
+h_simp : h_gamma, gamma=0, m=0;
+
+subst(h_gamma, h, trans_eq)$
+subst(l_gamma, l, %)$
+subst(0, m, %)$
+trans_eq2 : subst(0, gamma, %);
+
+c : 2.99792458e8$
+plot2d([trans_eq2], [f,0.1e9,1.4e9], [y, -1000, 1000]), t = 50e-3, d=100e-3, kappa=2, k_0 = 2*%pi*f/c$
+f_sol : find_root(trans_eq2, f, 0.8e9, 1e9), t = 50e-3, d = 100e-3, kappa = 2, k_0 = 2*%pi*f/c;
+h_simp: float(2*%pi*f_sol/c);
+sqrt(kappa)*2*%pi*f_sol/c, kappa=2$
+l_simp: float(%);
+
+%pi*a/(a-d-sqrt(kappa)), a=150e-3, d=100e-3, kappa=2;
+float(%);
+
diff --git a/examples/maxwell/maxwell-2d.py b/examples/maxwell/maxwell-2d.py
new file mode 100644
index 0000000000000000000000000000000000000000..33681ebcf6e3649f5a0a0a94ec76b0c18203623c
--- /dev/null
+++ b/examples/maxwell/maxwell-2d.py
@@ -0,0 +1,155 @@
+# Hedge - the Hybrid'n'Easy DG Environment
+# Copyright (C) 2007 Andreas Kloeckner
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+"Maxwell's equation example with fixed material coefficients"
+
+
+from __future__ import division
+import numpy.linalg as la
+
+
+def main(write_output=True):
+ from math import sqrt, pi, exp
+ from os.path import join
+
+ from hedge.backends import guess_run_context
+ rcon = guess_run_context()
+
+ epsilon0 = 8.8541878176e-12 # C**2 / (N m**2)
+ mu0 = 4*pi*1e-7 # N/A**2.
+ epsilon = 1*epsilon0
+ mu = 1*mu0
+
+ output_dir = "maxwell-2d"
+ import os
+ if not os.access(output_dir, os.F_OK):
+ os.makedirs(output_dir)
+
+ from hedge.mesh.generator import make_disk_mesh
+ mesh = make_disk_mesh(r=0.5, max_area=1e-3)
+
+ if rcon.is_head_rank:
+ mesh_data = rcon.distribute_mesh(mesh)
+ else:
+ mesh_data = rcon.receive_mesh()
+
+ class CurrentSource:
+ shape = (3,)
+
+ def __call__(self, x, el):
+ return [0,0,exp(-80*la.norm(x))]
+
+ order = 3
+ final_time = 1e-8
+ discr = rcon.make_discretization(mesh_data, order=order,
+ debug=["cuda_no_plan"])
+
+ from hedge.visualization import VtkVisualizer
+ if write_output:
+ vis = VtkVisualizer(discr, rcon, join(output_dir, "em-%d" % order))
+
+ if rcon.is_head_rank:
+ print "order %d" % order
+ print "#elements=", len(mesh.elements)
+
+ from hedge.mesh import TAG_ALL, TAG_NONE
+ from hedge.models.em import TMMaxwellOperator
+ from hedge.data import make_tdep_given, TimeIntervalGivenFunction
+ op = TMMaxwellOperator(epsilon, mu, flux_type=1,
+ current=TimeIntervalGivenFunction(
+ make_tdep_given(CurrentSource()), off_time=final_time/10),
+ absorb_tag=TAG_ALL, pec_tag=TAG_NONE)
+ fields = op.assemble_eh(discr=discr)
+
+ from hedge.timestep import LSRK4TimeStepper
+ stepper = LSRK4TimeStepper()
+ from time import time
+ last_tstep = time()
+ t = 0
+
+ # diagnostics setup ---------------------------------------------------
+ from pytools.log import LogManager, add_general_quantities, \
+ add_simulation_quantities, add_run_info
+
+ if write_output:
+ log_file_name = join(output_dir, "maxwell-%d.dat" % order)
+ else:
+ log_file_name = None
+
+ logmgr = LogManager(log_file_name, "w", rcon.communicator)
+ add_run_info(logmgr)
+ add_general_quantities(logmgr)
+ add_simulation_quantities(logmgr)
+ discr.add_instrumentation(logmgr)
+ stepper.add_instrumentation(logmgr)
+
+ from pytools.log import IntervalTimer
+ vis_timer = IntervalTimer("t_vis", "Time spent visualizing")
+ logmgr.add_quantity(vis_timer)
+
+ from hedge.log import EMFieldGetter, add_em_quantities
+ field_getter = EMFieldGetter(discr, op, lambda: fields)
+ add_em_quantities(logmgr, op, field_getter)
+
+ logmgr.add_watches(["step.max", "t_sim.max",
+ ("W_field", "W_el+W_mag"), "t_step.max"])
+
+ # timestep loop -------------------------------------------------------
+ rhs = op.bind(discr)
+
+ try:
+ from hedge.timestep import times_and_steps
+ step_it = times_and_steps(
+ final_time=final_time, logmgr=logmgr,
+ max_dt_getter=lambda t: op.estimate_timestep(discr,
+ stepper=stepper, t=t, fields=fields))
+
+ for step, t, dt in step_it:
+ if step % 10 == 0 and write_output:
+ e, h = op.split_eh(fields)
+ visf = vis.make_file(join(output_dir, "em-%d-%04d" % (order, step)))
+ vis.add_data(visf,
+ [
+ ("e", discr.convert_volume(e, "numpy")),
+ ("h", discr.convert_volume(h, "numpy")),
+ ],
+ time=t, step=step
+ )
+ visf.close()
+
+ fields = stepper(fields, t, dt, rhs)
+
+ assert discr.norm(fields) < 0.03
+ finally:
+ if write_output:
+ vis.close()
+
+ logmgr.close()
+ discr.close()
+
+if __name__ == "__main__":
+ import cProfile as profile
+ #profile.run("main()", "wave2d.prof")
+ main()
+
+
+
+
+# entry points for py.test ----------------------------------------------------
+from pytools.test import mark_test
+@mark_test.long
+def test_maxwell_2d():
+ main(write_output=False)
diff --git a/examples/maxwell/maxwell-2d/maxwell-3.dat b/examples/maxwell/maxwell-2d/maxwell-3.dat
new file mode 100644
index 0000000000000000000000000000000000000000..e428446bf3a175943f62f70e73317555571f8993
Binary files /dev/null and b/examples/maxwell/maxwell-2d/maxwell-3.dat differ
diff --git a/examples/maxwell/maxwell-pml.py b/examples/maxwell/maxwell-pml.py
new file mode 100644
index 0000000000000000000000000000000000000000..e365d80471dd12a45ab1e0ca64ac55f8210c2ced
--- /dev/null
+++ b/examples/maxwell/maxwell-pml.py
@@ -0,0 +1,243 @@
+"""Hedge is the Hybrid'n'Easy Discontinuous Galerkin Environment."""
+
+from __future__ import division
+
+__copyright__ = "Copyright (C) 2007 Andreas Kloeckner"
+
+__license__ = """
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+"""
+
+
+
+
+import numpy as np
+
+
+
+
+def make_mesh(a, b, pml_width=0.25, **kwargs):
+ from meshpy.geometry import GeometryBuilder, make_circle
+ geob = GeometryBuilder()
+
+ circle_centers = [(-1.5, 0), (1.5, 0)]
+ for cent in circle_centers:
+ geob.add_geometry(*make_circle(1, cent))
+
+ geob.wrap_in_box(1)
+ geob.wrap_in_box(pml_width)
+
+ mesh_mod = geob.mesher_module()
+ mi = mesh_mod.MeshInfo()
+ geob.set(mi)
+
+ mi.set_holes(circle_centers)
+
+ built_mi = mesh_mod.build(mi, **kwargs)
+
+ def boundary_tagger(fvi, el, fn, points):
+ return []
+
+ from hedge.mesh import make_conformal_mesh_ext
+ from hedge.mesh.element import Triangle
+ pts = np.asarray(built_mi.points, dtype=np.float64)
+ return make_conformal_mesh_ext(
+ pts,
+ [Triangle(i, el, pts)
+ for i, el in enumerate(built_mi.elements)],
+ boundary_tagger)
+
+
+
+
+def main(write_output=True):
+ from hedge.timestep.runge_kutta import LSRK4TimeStepper
+ from math import sqrt, pi, exp
+
+ from hedge.backends import guess_run_context
+ rcon = guess_run_context()
+
+ epsilon0 = 8.8541878176e-12 # C**2 / (N m**2)
+ mu0 = 4*pi*1e-7 # N/A**2.
+ epsilon = 1*epsilon0
+ mu = 1*mu0
+
+ c = 1/sqrt(mu*epsilon)
+
+ pml_width = 0.5
+ #mesh = make_mesh(a=np.array((-1,-1,-1)), b=np.array((1,1,1)),
+ #mesh = make_mesh(a=np.array((-3,-3)), b=np.array((3,3)),
+ mesh = make_mesh(a=np.array((-1,-1)), b=np.array((1,1)),
+ #mesh = make_mesh(a=np.array((-2,-2)), b=np.array((2,2)),
+ pml_width=pml_width, max_volume=0.01)
+
+ if rcon.is_head_rank:
+ mesh_data = rcon.distribute_mesh(mesh)
+ else:
+ mesh_data = rcon.receive_mesh()
+
+ class Current:
+ def volume_interpolant(self, t, discr):
+ from hedge.tools import make_obj_array
+
+ result = discr.volume_zeros(kind="numpy", dtype=np.float64)
+
+ omega = 6*c
+ if omega*t > 2*pi:
+ return make_obj_array([result, result, result])
+
+ x = make_obj_array(discr.nodes.T)
+ r = np.sqrt(np.dot(x, x))
+
+ idx = r<0.3
+ result[idx] = (1+np.cos(pi*r/0.3))[idx] \
+ *np.sin(omega*t)**3
+
+ result = discr.convert_volume(result, kind=discr.compute_kind,
+ dtype=discr.default_scalar_type)
+ return make_obj_array([-result, result, result])
+
+ order = 3
+ discr = rcon.make_discretization(mesh_data, order=order,
+ debug=["cuda_no_plan"])
+
+ from hedge.visualization import VtkVisualizer
+ if write_output:
+ vis = VtkVisualizer(discr, rcon, "em-%d" % order)
+
+ from hedge.mesh import TAG_ALL, TAG_NONE
+ from hedge.data import GivenFunction, TimeHarmonicGivenFunction, TimeIntervalGivenFunction
+ from hedge.models.em import MaxwellOperator
+ from hedge.models.pml import \
+ AbarbanelGottliebPMLMaxwellOperator, \
+ AbarbanelGottliebPMLTMMaxwellOperator, \
+ AbarbanelGottliebPMLTEMaxwellOperator
+
+ op = AbarbanelGottliebPMLTEMaxwellOperator(epsilon, mu, flux_type=1,
+ current=Current(),
+ pec_tag=TAG_ALL,
+ absorb_tag=TAG_NONE,
+ add_decay=True
+ )
+
+ fields = op.assemble_ehpq(discr=discr)
+
+ stepper = LSRK4TimeStepper()
+
+ if rcon.is_head_rank:
+ print "order %d" % order
+ print "#elements=", len(mesh.elements)
+
+ # diagnostics setup ---------------------------------------------------
+ from pytools.log import LogManager, add_general_quantities, \
+ add_simulation_quantities, add_run_info
+
+ if write_output:
+ log_file_name = "maxwell-%d.dat" % order
+ else:
+ log_file_name = None
+
+ logmgr = LogManager(log_file_name, "w", rcon.communicator)
+ add_run_info(logmgr)
+ add_general_quantities(logmgr)
+ add_simulation_quantities(logmgr)
+ discr.add_instrumentation(logmgr)
+ stepper.add_instrumentation(logmgr)
+
+ from pytools.log import IntervalTimer
+ vis_timer = IntervalTimer("t_vis", "Time spent visualizing")
+ logmgr.add_quantity(vis_timer)
+
+ from hedge.log import EMFieldGetter, add_em_quantities
+ field_getter = EMFieldGetter(discr, op, lambda: fields)
+ add_em_quantities(logmgr, op, field_getter)
+
+ logmgr.add_watches(["step.max", "t_sim.max", ("W_field", "W_el+W_mag"), "t_step.max"])
+
+ from hedge.log import LpNorm
+ class FieldIdxGetter:
+ def __init__(self, whole_getter, idx):
+ self.whole_getter = whole_getter
+ self.idx = idx
+
+ def __call__(self):
+ return self.whole_getter()[self.idx]
+
+ # timestep loop -------------------------------------------------------
+
+ t = 0
+ pml_coeff = op.coefficients_from_width(discr, width=pml_width)
+ rhs = op.bind(discr, pml_coeff)
+
+ try:
+ from hedge.timestep import times_and_steps
+ step_it = times_and_steps(
+ final_time=4/c, logmgr=logmgr,
+ max_dt_getter=lambda t: op.estimate_timestep(discr,
+ stepper=stepper, t=t, fields=fields))
+
+ for step, t, dt in step_it:
+ if step % 10 == 0 and write_output:
+ e, h, p, q = op.split_ehpq(fields)
+ visf = vis.make_file("em-%d-%04d" % (order, step))
+ #pml_rhs_e, pml_rhs_h, pml_rhs_p, pml_rhs_q = \
+ #op.split_ehpq(rhs(t, fields))
+ j = Current().volume_interpolant(t, discr)
+ vis.add_data(visf, [
+ ("e", discr.convert_volume(e, "numpy")),
+ ("h", discr.convert_volume(h, "numpy")),
+ ("p", discr.convert_volume(p, "numpy")),
+ ("q", discr.convert_volume(q, "numpy")),
+ ("j", discr.convert_volume(j, "numpy")),
+ #("pml_rhs_e", pml_rhs_e),
+ #("pml_rhs_h", pml_rhs_h),
+ #("pml_rhs_p", pml_rhs_p),
+ #("pml_rhs_q", pml_rhs_q),
+ #("max_rhs_e", max_rhs_e),
+ #("max_rhs_h", max_rhs_h),
+ #("max_rhs_p", max_rhs_p),
+ #("max_rhs_q", max_rhs_q),
+ ],
+ time=t, step=step)
+ visf.close()
+
+ fields = stepper(fields, t, dt, rhs)
+
+ _, _, energies_data = logmgr.get_expr_dataset("W_el+W_mag")
+ energies = [value for tick_nbr, value in energies_data]
+
+ assert energies[-1] < max(energies) * 1e-2
+
+ finally:
+ logmgr.close()
+
+ if write_output:
+ vis.close()
+
+if __name__ == "__main__":
+ main()
+
+
+
+
+# entry points for py.test ----------------------------------------------------
+from pytools.test import mark_test
+@mark_test.long
+def test_maxwell_pml():
+ main(write_output=False)
diff --git a/examples/maxwell/notes.tm b/examples/maxwell/notes.tm
new file mode 100644
index 0000000000000000000000000000000000000000..bd159b24881bbcbd6561a2e048c8cd43dff79f8f
--- /dev/null
+++ b/examples/maxwell/notes.tm
@@ -0,0 +1,403 @@
+
+
+