Skip to content
Snippets Groups Projects
cavities.py 7.99 KiB
Newer Older
# 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 <http://www.gnu.org/licenses/>.


from __future__ import division
Andreas Klöckner's avatar
Andreas Klöckner committed
from __future__ import absolute_import
from __future__ import print_function
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={}):
Andreas Klöckner's avatar
Andreas Klöckner committed
    from grudge.mesh.generator import make_cylinder_mesh, make_box_mesh
    from grudge.tools import EOCRecorder, to_obj_array
    from math import sqrt, pi  # noqa
    from analytic_solutions import (  # noqa
            RealPartAdapter,
            SplitComplexAdapter,
            CylindricalFieldAdapter,
            CylindricalCavityMode,
            RectangularWaveguideMode,
            RectangularCavityMode)
Andreas Klöckner's avatar
Andreas Klöckner committed
    from grudge.models.em import MaxwellOperator

    logging.basicConfig(level=logging.DEBUG)

Andreas Klöckner's avatar
Andreas Klöckner committed
    from grudge.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.sym_operator(),
                **extra_discr_args)

Andreas Klöckner's avatar
Andreas Klöckner committed
        from grudge.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:
Andreas Klöckner's avatar
Andreas Klöckner committed
            print("---------------------------------------------")
            print("order %d" % order)
            print("---------------------------------------------")
            print("#elements=", len(mesh.elements))
Andreas Klöckner's avatar
Andreas Klöckner committed
        from grudge.timestep.runge_kutta import LSRK4TimeStepper
        stepper = LSRK4TimeStepper(dtype=discr.default_scalar_type, rcon=rcon)
Andreas Klöckner's avatar
Andreas Klöckner committed
        #from grudge.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)

Andreas Klöckner's avatar
Andreas Klöckner committed
        from grudge.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:
Andreas Klöckner's avatar
Andreas Klöckner committed
            from grudge.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:
Andreas Klöckner's avatar
Andreas Klöckner committed
            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)