예제 #1
0
def test_kv_with_no_charge():
    from random import seed
    seed(0)

    from pyrticle.units import SIUnitsWithNaturalConstants
    units = SIUnitsWithNaturalConstants()

    # discretization setup ----------------------------------------------------
    from hedge.mesh import make_cylinder_mesh
    from hedge.backends import guess_run_context

    rcon = guess_run_context([])

    tube_length = 100 * units.MM
    mesh = make_cylinder_mesh(radius=25 * units.MM,
                              height=tube_length,
                              periodic=True)

    discr = rcon.make_discretization(mesh, order=3)

    dt = discr.dt_factor(units.VACUUM_LIGHT_SPEED()) / 2
    final_time = 1 * units.M / units.VACUUM_LIGHT_SPEED()
    nsteps = int(final_time / dt) + 1
    dt = final_time / nsteps

    # particles setup ---------------------------------------------------------
    from pyrticle.cloud import PicMethod
    from pyrticle.deposition.shape import ShapeFunctionDepositor
    from pyrticle.pusher import MonomialParticlePusher

    method = PicMethod(discr, units, ShapeFunctionDepositor(),
                       MonomialParticlePusher(), 3, 3)

    nparticles = 10000
    cloud_charge = 1e-9 * units.C
    electrons_per_particle = cloud_charge / nparticles / units.EL_CHARGE

    el_energy = 5.2e6 * units.EV
    gamma = el_energy / units.EL_REST_ENERGY()
    beta = (1 - 1 / gamma**2)**0.5

    from pyrticle.distribution import KVZIntervalBeam
    beam = KVZIntervalBeam(units,
                           total_charge=0,
                           p_charge=0,
                           p_mass=electrons_per_particle * units.EL_MASS,
                           radii=2 * [2.5 * units.MM],
                           emittances=2 * [5 * units.MM * units.MRAD],
                           z_length=5 * units.MM,
                           z_pos=10 * units.MM,
                           beta=beta)

    state = method.make_state()
    method.add_particles(state, beam.generate_particles(), nparticles)

    # diagnostics setup -------------------------------------------------------
    from pytools.log import LogManager
    from pyrticle.log import add_beam_quantities, StateObserver
    observer = StateObserver(method, None)
    logmgr = LogManager(mode="w")
    add_beam_quantities(logmgr, observer, axis=0, beam_axis=2)

    from pyrticle.distribution import KVPredictedRadius
    logmgr.add_quantity(
        KVPredictedRadius(dt,
                          beam_v=beta * units.VACUUM_LIGHT_SPEED(),
                          predictor=beam.get_rms_predictor(axis=0),
                          suffix="x_rms"))
    logmgr.add_quantity(
        KVPredictedRadius(dt,
                          beam_v=beta * units.VACUUM_LIGHT_SPEED(),
                          predictor=beam.get_total_predictor(axis=0),
                          suffix="x_total"))

    # timestep loop -----------------------------------------------------------
    vel = method.velocities(state)
    from hedge.tools import join_fields

    def rhs(t, y):
        return join_fields([
            vel,
            0 * vel,
            0,  # drecon
        ])

    from hedge.timestep.runge_kutta import LSRK4TimeStepper
    stepper = LSRK4TimeStepper()
    t = 0

    from pyrticle.cloud import TimesteppablePicState
    ts_state = TimesteppablePicState(method, state)

    for step in xrange(nsteps):
        observer.set_fields_and_state(None, ts_state.state)

        logmgr.tick()

        ts_state = stepper(ts_state, t, dt, rhs)
        method.upkeep(ts_state.state)

        t += dt

    logmgr.tick()

    _, _, err_table = logmgr.get_expr_dataset(
        "(rx_rms-rx_rms_theory)/rx_rms_theory")
    rel_max_rms_error = max(err for step, err in err_table)
    assert rel_max_rms_error < 0.01
예제 #2
0
파일: driver.py 프로젝트: gimac/pyrticle
class PICRunner(object):
    def __init__(self):
        from pyrticle.units import SIUnitsWithNaturalConstants
        self.units = units = SIUnitsWithNaturalConstants()

        ui = PICCPyUserInterface(units)
        setup = self.setup = ui.gather()

        from pytools.log import LogManager
        import os.path
        self.logmgr = LogManager(os.path.join(
            setup.output_path, "pic.dat"), "w")

        from hedge.backends import guess_run_context
        self.rcon = guess_run_context([])

        if self.rcon.is_head_rank:
            mesh = self.rcon.distribute_mesh(setup.mesh)
        else:
            mesh = self.rcon.receive_mesh()

        self.discr = discr = \
                self.rcon.make_discretization(mesh, 
                        order=setup.element_order,
                        debug=setup.dg_debug)

        self.logmgr.set_constant("elements_total", len(setup.mesh.elements))
        self.logmgr.set_constant("elements_local", len(mesh.elements))
        self.logmgr.set_constant("element_order", setup.element_order)

        # em operator ---------------------------------------------------------
        maxwell_kwargs = {
                "epsilon": units.EPSILON0, 
                "mu": units.MU0, 
                "flux_type": setup.maxwell_flux_type,
                "bdry_flux_type": setup.maxwell_bdry_flux_type
                }

        if discr.dimensions == 3:
            from hedge.models.em import MaxwellOperator
            self.maxwell_op = MaxwellOperator(**maxwell_kwargs)
        elif discr.dimensions == 2:
            from hedge.models.em import TEMaxwellOperator
            self.maxwell_op = TEMaxwellOperator(**maxwell_kwargs)
        else:
            raise ValueError, "invalid mesh dimension"

        if setup.chi is not None:
            from pyrticle.hyperbolic import ECleaningMaxwellOperator
            self.maxwell_op = ECleaningMaxwellOperator(self.maxwell_op, 
                    chi=setup.chi, 
                    phi_decay=setup.phi_decay)

            if setup.phi_filter is not None:
                from pyrticle.hyperbolic import PhiFilter
                from hedge.discretization import Filter, ExponentialFilterResponseFunction
                em_filters.append(
                        PhiFilter(maxwell_op, Filter(discr,
                            ExponentialFilterResponseFunction(*setup.phi_filter))))

        # timestepping setup --------------------------------------------------
        goal_dt = self.maxwell_op.estimate_timestep(discr) * setup.dt_scale
        self.nsteps = int(setup.final_time/goal_dt)+1
        self.dt = setup.final_time/self.nsteps

        self.stepper = setup.timestepper_maker(self.dt)

        # particle setup ------------------------------------------------------
        from pyrticle.cloud import PicMethod, PicState, \
                optimize_shape_bandwidth, \
                guess_shape_bandwidth

        method = self.method = PicMethod(discr, units, 
                setup.depositor, setup.pusher,
                dimensions_pos=setup.dimensions_pos, 
                dimensions_velocity=setup.dimensions_velocity, 
                debug=setup.debug)

        self.state = method.make_state()
        method.add_particles( 
                self.state,
                setup.distribution.generate_particles(),
                setup.nparticles)

        self.total_charge = setup.nparticles*setup.distribution.mean()[2][0]
        if isinstance(setup.shape_bandwidth, str):
            if setup.shape_bandwidth == "optimize":
                optimize_shape_bandwidth(method, self.state,
                        setup.distribution.get_rho_interpolant(
                            discr, self.total_charge),
                        setup.shape_exponent)
            elif setup.shape_bandwidth == "guess":
                guess_shape_bandwidth(method, self.state, setup.shape_exponent)
            else:
                raise ValueError, "invalid shape bandwidth setting '%s'" % (
                        setup.shape_bandwidth)
        else:
            from pyrticle._internal import PolynomialShapeFunction
            method.depositor.set_shape_function(
                    self.state,
                    PolynomialShapeFunction(
                        float(setup.shape_bandwidth),
                        method.mesh_data.dimensions,
                        setup.shape_exponent,
                        ))

        # initial condition ---------------------------------------------------
        if "no_ic" in setup.debug:
            self.fields = self.maxwell_op.assemble_eh(discr=discr)
        else:
            from pyrticle.cloud import compute_initial_condition
            self.fields = compute_initial_condition(self.rcon, discr, method, self.state,
                    maxwell_op=self.maxwell_op, 
                    potential_bc=setup.potential_bc, 
                    force_zero=False)

        # rhs calculators -----------------------------------------------------
        from pyrticle.cloud import \
                FieldRhsCalculator, \
                FieldToParticleRhsCalculator, \
                ParticleRhsCalculator, \
                ParticleToFieldRhsCalculator
        self.f_rhs_calculator = FieldRhsCalculator(self.method, self.maxwell_op)
        self.p_rhs_calculator = ParticleRhsCalculator(self.method, self.maxwell_op)
        self.f2p_rhs_calculator = FieldToParticleRhsCalculator(self.method, self.maxwell_op)
        self.p2f_rhs_calculator = ParticleToFieldRhsCalculator(self.method, self.maxwell_op)

        # instrumentation setup -----------------------------------------------
        self.add_instrumentation(self.logmgr)

    def add_instrumentation(self, logmgr):
        from pytools.log import \
                add_simulation_quantities, \
                add_general_quantities, \
                add_run_info, ETA
        from pyrticle.log import add_particle_quantities, add_field_quantities, \
                add_beam_quantities, add_currents

        setup = self.setup

        from pyrticle.log import StateObserver
        self.observer = StateObserver(self.method, self.maxwell_op)
        self.observer.set_fields_and_state(self.fields, self.state)

        add_run_info(logmgr)
        add_general_quantities(logmgr)
        add_simulation_quantities(logmgr)
        add_particle_quantities(logmgr, self.observer)
        add_field_quantities(logmgr, self.observer)

        if setup.beam_axis is not None and setup.beam_diag_axis is not None:
            add_beam_quantities(logmgr, self.observer, 
                    axis=setup.beam_diag_axis, 
                    beam_axis=setup.beam_axis)

        if setup.tube_length is not None:
            from hedge.tools import unit_vector
            add_currents(logmgr, self.observer, 
                    unit_vector(self.method.dimensions_velocity, setup.beam_axis), 
                    setup.tube_length)

        self.method.add_instrumentation(logmgr, self.observer)

        self.f_rhs_calculator.add_instrumentation(logmgr)

        if hasattr(self.stepper, "add_instrumentation"):
            self.stepper.add_instrumentation(logmgr)

        mean_beta = self.method.mean_beta(self.state)
        gamma = self.method.units.gamma_from_beta(mean_beta)

        logmgr.set_constant("dt", self.dt)
        logmgr.set_constant("beta", mean_beta)
        logmgr.set_constant("gamma", gamma)
        logmgr.set_constant("v", mean_beta*self.units.VACUUM_LIGHT_SPEED())
        logmgr.set_constant("Q0", self.total_charge)
        logmgr.set_constant("n_part_0", setup.nparticles)
        logmgr.set_constant("pmass", setup.distribution.mean()[3][0])
        logmgr.set_constant("chi", setup.chi)
        logmgr.set_constant("phi_decay", setup.phi_decay)
        logmgr.set_constant("shape_radius_setup", setup.shape_bandwidth)
        logmgr.set_constant("shape_radius", self.method.depositor.shape_function.radius)
        logmgr.set_constant("shape_exponent", self.method.depositor.shape_function.exponent)

        from pytools.log import IntervalTimer
        self.vis_timer = IntervalTimer("t_vis", "Time spent visualizing")
        logmgr.add_quantity(self.vis_timer)

        logmgr.add_quantity(ETA(self.nsteps))

        logmgr.add_watches(setup.watch_vars)

    def inner_run(self): 
        t = 0
        
        setup = self.setup
        setup.hook_startup(self)

        vis_order = setup.vis_order
        if vis_order is None:
            vis_order = setup.element_order

        if vis_order != setup.element_order:
            vis_discr = self.rcon.make_discretization(self.discr.mesh, 
                            order=vis_order, debug=setup.dg_debug)

            from hedge.discretization import Projector
            vis_proj = Projector(self.discr, vis_discr)
        else:
            vis_discr = self.discr

            def vis_proj(f):
                return f

        from hedge.visualization import SiloVisualizer
        vis = SiloVisualizer(vis_discr)

        fields = self.fields
        self.observer.set_fields_and_state(fields, self.state)

        from hedge.tools import make_obj_array
        from pyrticle.cloud import TimesteppablePicState

        def visualize(observer):
            sub_timer = self.vis_timer.start_sub_timer()
            import os.path
            visf = vis.make_file(os.path.join(
                setup.output_path, setup.vis_pattern % step))

            self.method.add_to_vis(vis, visf, observer.state, time=t, step=step)
            vis.add_data(visf, 
                    [(name, vis_proj(fld))
                        for name, fld in setup.hook_vis_quantities(observer)],
                    time=t, step=step)
            setup.hook_visualize(self, vis, visf, observer)

            visf.close()
            sub_timer.stop().submit()

        from hedge.timestep.multirate_ab import TwoRateAdamsBashforthTimeStepper 
        if not isinstance(self.stepper, TwoRateAdamsBashforthTimeStepper): 
            def rhs(t, fields_and_state):
                fields, ts_state = fields_and_state
                state_f = lambda: ts_state.state
                fields_f = lambda: fields

                fields_rhs = (
                        self.f_rhs_calculator(t, fields_f, state_f)
                        + self.p2f_rhs_calculator(t, fields_f, state_f))
                state_rhs = (
                        self.p_rhs_calculator(t, fields_f, state_f)
                        + self.f2p_rhs_calculator(t, fields_f, state_f))

                return make_obj_array([fields_rhs, state_rhs])
            step_args = (self.dt, rhs)
        else:
            def add_unwrap(rhs):
                def unwrapping_rhs(t, fields, ts_state):
                    return rhs(t, fields, lambda: ts_state().state)
                return unwrapping_rhs

            step_args = ((
                    add_unwrap(self.f_rhs_calculator),
                    add_unwrap(self.p2f_rhs_calculator),
                    add_unwrap(self.f2p_rhs_calculator),
                    add_unwrap(self.p_rhs_calculator),
                    ),)

        y = make_obj_array([
            fields, 
            TimesteppablePicState(self.method, self.state)
            ])
        del self.state

        try:
            from hedge.timestep import times_and_steps
            step_it = times_and_steps(
                    max_steps=self.nsteps,
                    logmgr=self.logmgr,
                    max_dt_getter=lambda t: self.dt)

            for step, t, dt in step_it:
                self.method.upkeep(y[1].state)

                if step % setup.vis_interval == 0:
                    visualize(self.observer)

                y = self.stepper(y, t, *step_args)

                fields, ts_state = y
                self.observer.set_fields_and_state(fields, ts_state.state)

                setup.hook_after_step(self, self.observer)
        finally:
            vis.close()
            self.discr.close()
            self.logmgr.save()

        setup.hook_when_done(self)

    def run(self):
        if self.setup.profile_output_filename is not None:
            from cProfile import Profile
            prof = Profile()
            try:
                prof.runcall(self.inner_run)
            finally:
                from lsprofcalltree import KCacheGrind
                kg = KCacheGrind(prof)
                kg.output(open(self.setup.profile_output_filename, "w"))
        else:
            self.inner_run()
예제 #3
0
def test_kv_with_no_charge():
    from random import seed
    seed(0)

    from pyrticle.units import SIUnitsWithNaturalConstants
    units = SIUnitsWithNaturalConstants()

    # discretization setup ----------------------------------------------------
    from hedge.mesh import make_cylinder_mesh
    from hedge.backends import guess_run_context

    rcon = guess_run_context([])

    tube_length = 100*units.MM
    mesh = make_cylinder_mesh(radius=25*units.MM, height=tube_length, periodic=True)

    discr = rcon.make_discretization(mesh, order=3)

    dt = discr.dt_factor(units.VACUUM_LIGHT_SPEED()) / 2
    final_time = 1*units.M/units.VACUUM_LIGHT_SPEED()
    nsteps = int(final_time/dt)+1
    dt = final_time/nsteps

    # particles setup ---------------------------------------------------------
    from pyrticle.cloud import PicMethod
    from pyrticle.deposition.shape import ShapeFunctionDepositor
    from pyrticle.pusher import MonomialParticlePusher

    method = PicMethod(discr, units,
            ShapeFunctionDepositor(),
            MonomialParticlePusher(),
            3, 3)

    nparticles = 10000
    cloud_charge = 1e-9 * units.C
    electrons_per_particle = cloud_charge/nparticles/units.EL_CHARGE

    el_energy = 5.2e6 * units.EV
    gamma = el_energy/units.EL_REST_ENERGY()
    beta = (1-1/gamma**2)**0.5

    from pyrticle.distribution import KVZIntervalBeam
    beam = KVZIntervalBeam(units,
            total_charge=0,
            p_charge=0,
            p_mass=electrons_per_particle*units.EL_MASS,
            radii=2*[2.5*units.MM],
            emittances=2*[5 * units.MM * units.MRAD],
            z_length=5*units.MM,
            z_pos=10*units.MM,
            beta=beta)

    state = method.make_state()
    method.add_particles(state, beam.generate_particles(), nparticles)

    # diagnostics setup -------------------------------------------------------
    from pytools.log import LogManager
    from pyrticle.log import add_beam_quantities, StateObserver
    observer = StateObserver(method, None)
    logmgr = LogManager(mode="w")
    add_beam_quantities(logmgr, observer, axis=0, beam_axis=2)

    from pyrticle.distribution import KVPredictedRadius
    logmgr.add_quantity(KVPredictedRadius(dt,
        beam_v=beta*units.VACUUM_LIGHT_SPEED(),
        predictor=beam.get_rms_predictor(axis=0),
        suffix="x_rms"))
    logmgr.add_quantity(KVPredictedRadius(dt,
        beam_v=beta*units.VACUUM_LIGHT_SPEED(),
        predictor=beam.get_total_predictor(axis=0),
        suffix="x_total"))

    # timestep loop -----------------------------------------------------------
    vel = method.velocities(state)
    from hedge.tools import join_fields
    def rhs(t, y):
        return join_fields([
            vel,
            0*vel,
            0, # drecon
            ])

    from hedge.timestep.runge_kutta import LSRK4TimeStepper
    stepper = LSRK4TimeStepper()
    t = 0

    from pyrticle.cloud import TimesteppablePicState
    ts_state = TimesteppablePicState(method, state)

    for step in xrange(nsteps):
        observer.set_fields_and_state(None, ts_state.state)

        logmgr.tick()

        ts_state = stepper(ts_state, t, dt, rhs)
        method.upkeep(ts_state.state)

        t += dt

    logmgr.tick()

    _, _, err_table = logmgr.get_expr_dataset("(rx_rms-rx_rms_theory)/rx_rms_theory")
    rel_max_rms_error = max(err for step, err in err_table)
    assert rel_max_rms_error < 0.01
예제 #4
0
class PICRunner(object):
    def __init__(self):
        from pyrticle.units import SIUnitsWithNaturalConstants
        self.units = units = SIUnitsWithNaturalConstants()

        ui = PICCPyUserInterface(units)
        setup = self.setup = ui.gather()

        from pytools.log import LogManager
        import os.path
        self.logmgr = LogManager(os.path.join(setup.output_path, "pic.dat"),
                                 "w")

        from hedge.backends import guess_run_context
        self.rcon = guess_run_context([])

        if self.rcon.is_head_rank:
            mesh = self.rcon.distribute_mesh(setup.mesh)
        else:
            mesh = self.rcon.receive_mesh()

        self.discr = discr = \
                self.rcon.make_discretization(mesh,
                        order=setup.element_order,
                        debug=setup.dg_debug)

        self.logmgr.set_constant("elements_total", len(setup.mesh.elements))
        self.logmgr.set_constant("elements_local", len(mesh.elements))
        self.logmgr.set_constant("element_order", setup.element_order)

        # em operator ---------------------------------------------------------
        maxwell_kwargs = {
            "epsilon": units.EPSILON0,
            "mu": units.MU0,
            "flux_type": setup.maxwell_flux_type,
            "bdry_flux_type": setup.maxwell_bdry_flux_type
        }

        if discr.dimensions == 3:
            from hedge.models.em import MaxwellOperator
            self.maxwell_op = MaxwellOperator(**maxwell_kwargs)
        elif discr.dimensions == 2:
            from hedge.models.em import TEMaxwellOperator
            self.maxwell_op = TEMaxwellOperator(**maxwell_kwargs)
        else:
            raise ValueError, "invalid mesh dimension"

        if setup.chi is not None:
            from pyrticle.hyperbolic import ECleaningMaxwellOperator
            self.maxwell_op = ECleaningMaxwellOperator(
                self.maxwell_op, chi=setup.chi, phi_decay=setup.phi_decay)

            if setup.phi_filter is not None:
                from pyrticle.hyperbolic import PhiFilter
                from hedge.discretization import Filter, ExponentialFilterResponseFunction
                em_filters.append(
                    PhiFilter(
                        maxwell_op,
                        Filter(
                            discr,
                            ExponentialFilterResponseFunction(
                                *setup.phi_filter))))

        # timestepping setup --------------------------------------------------
        goal_dt = self.maxwell_op.estimate_timestep(discr) * setup.dt_scale
        self.nsteps = int(setup.final_time / goal_dt) + 1
        self.dt = setup.final_time / self.nsteps

        self.stepper = setup.timestepper_maker(self.dt)

        # particle setup ------------------------------------------------------
        from pyrticle.cloud import PicMethod, PicState, \
                optimize_shape_bandwidth, \
                guess_shape_bandwidth

        method = self.method = PicMethod(
            discr,
            units,
            setup.depositor,
            setup.pusher,
            dimensions_pos=setup.dimensions_pos,
            dimensions_velocity=setup.dimensions_velocity,
            debug=setup.debug)

        self.state = method.make_state()
        method.add_particles(self.state,
                             setup.distribution.generate_particles(),
                             setup.nparticles)

        self.total_charge = setup.nparticles * setup.distribution.mean()[2][0]
        if isinstance(setup.shape_bandwidth, str):
            if setup.shape_bandwidth == "optimize":
                optimize_shape_bandwidth(
                    method, self.state,
                    setup.distribution.get_rho_interpolant(
                        discr, self.total_charge), setup.shape_exponent)
            elif setup.shape_bandwidth == "guess":
                guess_shape_bandwidth(method, self.state, setup.shape_exponent)
            else:
                raise ValueError, "invalid shape bandwidth setting '%s'" % (
                    setup.shape_bandwidth)
        else:
            from pyrticle._internal import PolynomialShapeFunction
            method.depositor.set_shape_function(
                self.state,
                PolynomialShapeFunction(
                    float(setup.shape_bandwidth),
                    method.mesh_data.dimensions,
                    setup.shape_exponent,
                ))

        # initial condition ---------------------------------------------------
        if "no_ic" in setup.debug:
            self.fields = self.maxwell_op.assemble_eh(discr=discr)
        else:
            from pyrticle.cloud import compute_initial_condition
            self.fields = compute_initial_condition(
                self.rcon,
                discr,
                method,
                self.state,
                maxwell_op=self.maxwell_op,
                potential_bc=setup.potential_bc,
                force_zero=False)

        # rhs calculators -----------------------------------------------------
        from pyrticle.cloud import \
                FieldRhsCalculator, \
                FieldToParticleRhsCalculator, \
                ParticleRhsCalculator, \
                ParticleToFieldRhsCalculator
        self.f_rhs_calculator = FieldRhsCalculator(self.method,
                                                   self.maxwell_op)
        self.p_rhs_calculator = ParticleRhsCalculator(self.method,
                                                      self.maxwell_op)
        self.f2p_rhs_calculator = FieldToParticleRhsCalculator(
            self.method, self.maxwell_op)
        self.p2f_rhs_calculator = ParticleToFieldRhsCalculator(
            self.method, self.maxwell_op)

        # instrumentation setup -----------------------------------------------
        self.add_instrumentation(self.logmgr)

    def add_instrumentation(self, logmgr):
        from pytools.log import \
                add_simulation_quantities, \
                add_general_quantities, \
                add_run_info, ETA
        from pyrticle.log import add_particle_quantities, add_field_quantities, \
                add_beam_quantities, add_currents

        setup = self.setup

        from pyrticle.log import StateObserver
        self.observer = StateObserver(self.method, self.maxwell_op)
        self.observer.set_fields_and_state(self.fields, self.state)

        add_run_info(logmgr)
        add_general_quantities(logmgr)
        add_simulation_quantities(logmgr)
        add_particle_quantities(logmgr, self.observer)
        add_field_quantities(logmgr, self.observer)

        if setup.beam_axis is not None and setup.beam_diag_axis is not None:
            add_beam_quantities(logmgr,
                                self.observer,
                                axis=setup.beam_diag_axis,
                                beam_axis=setup.beam_axis)

        if setup.tube_length is not None:
            from hedge.tools import unit_vector
            add_currents(
                logmgr, self.observer,
                unit_vector(self.method.dimensions_velocity, setup.beam_axis),
                setup.tube_length)

        self.method.add_instrumentation(logmgr, self.observer)

        self.f_rhs_calculator.add_instrumentation(logmgr)

        if hasattr(self.stepper, "add_instrumentation"):
            self.stepper.add_instrumentation(logmgr)

        mean_beta = self.method.mean_beta(self.state)
        gamma = self.method.units.gamma_from_beta(mean_beta)

        logmgr.set_constant("dt", self.dt)
        logmgr.set_constant("beta", mean_beta)
        logmgr.set_constant("gamma", gamma)
        logmgr.set_constant("v", mean_beta * self.units.VACUUM_LIGHT_SPEED())
        logmgr.set_constant("Q0", self.total_charge)
        logmgr.set_constant("n_part_0", setup.nparticles)
        logmgr.set_constant("pmass", setup.distribution.mean()[3][0])
        logmgr.set_constant("chi", setup.chi)
        logmgr.set_constant("phi_decay", setup.phi_decay)
        logmgr.set_constant("shape_radius_setup", setup.shape_bandwidth)
        logmgr.set_constant("shape_radius",
                            self.method.depositor.shape_function.radius)
        logmgr.set_constant("shape_exponent",
                            self.method.depositor.shape_function.exponent)

        from pytools.log import IntervalTimer
        self.vis_timer = IntervalTimer("t_vis", "Time spent visualizing")
        logmgr.add_quantity(self.vis_timer)

        logmgr.add_quantity(ETA(self.nsteps))

        logmgr.add_watches(setup.watch_vars)

    def inner_run(self):
        t = 0

        setup = self.setup
        setup.hook_startup(self)

        vis_order = setup.vis_order
        if vis_order is None:
            vis_order = setup.element_order

        if vis_order != setup.element_order:
            vis_discr = self.rcon.make_discretization(self.discr.mesh,
                                                      order=vis_order,
                                                      debug=setup.dg_debug)

            from hedge.discretization import Projector
            vis_proj = Projector(self.discr, vis_discr)
        else:
            vis_discr = self.discr

            def vis_proj(f):
                return f

        from hedge.visualization import SiloVisualizer
        vis = SiloVisualizer(vis_discr)

        fields = self.fields
        self.observer.set_fields_and_state(fields, self.state)

        from hedge.tools import make_obj_array
        from pyrticle.cloud import TimesteppablePicState

        def visualize(observer):
            sub_timer = self.vis_timer.start_sub_timer()
            import os.path
            visf = vis.make_file(
                os.path.join(setup.output_path, setup.vis_pattern % step))

            self.method.add_to_vis(vis,
                                   visf,
                                   observer.state,
                                   time=t,
                                   step=step)
            vis.add_data(
                visf, [(name, vis_proj(fld))
                       for name, fld in setup.hook_vis_quantities(observer)],
                time=t,
                step=step)
            setup.hook_visualize(self, vis, visf, observer)

            visf.close()
            sub_timer.stop().submit()

        from hedge.timestep.multirate_ab import TwoRateAdamsBashforthTimeStepper
        if not isinstance(self.stepper, TwoRateAdamsBashforthTimeStepper):

            def rhs(t, fields_and_state):
                fields, ts_state = fields_and_state
                state_f = lambda: ts_state.state
                fields_f = lambda: fields

                fields_rhs = (self.f_rhs_calculator(t, fields_f, state_f) +
                              self.p2f_rhs_calculator(t, fields_f, state_f))
                state_rhs = (self.p_rhs_calculator(t, fields_f, state_f) +
                             self.f2p_rhs_calculator(t, fields_f, state_f))

                return make_obj_array([fields_rhs, state_rhs])

            step_args = (self.dt, rhs)
        else:

            def add_unwrap(rhs):
                def unwrapping_rhs(t, fields, ts_state):
                    return rhs(t, fields, lambda: ts_state().state)

                return unwrapping_rhs

            step_args = ((
                add_unwrap(self.f_rhs_calculator),
                add_unwrap(self.p2f_rhs_calculator),
                add_unwrap(self.f2p_rhs_calculator),
                add_unwrap(self.p_rhs_calculator),
            ), )

        y = make_obj_array(
            [fields, TimesteppablePicState(self.method, self.state)])
        del self.state

        try:
            from hedge.timestep import times_and_steps
            step_it = times_and_steps(max_steps=self.nsteps,
                                      logmgr=self.logmgr,
                                      max_dt_getter=lambda t: self.dt)

            for step, t, dt in step_it:
                self.method.upkeep(y[1].state)

                if step % setup.vis_interval == 0:
                    visualize(self.observer)

                y = self.stepper(y, t, *step_args)

                fields, ts_state = y
                self.observer.set_fields_and_state(fields, ts_state.state)

                setup.hook_after_step(self, self.observer)
        finally:
            vis.close()
            self.discr.close()
            self.logmgr.save()

        setup.hook_when_done(self)

    def run(self):
        if self.setup.profile_output_filename is not None:
            from cProfile import Profile
            prof = Profile()
            try:
                prof.runcall(self.inner_run)
            finally:
                from lsprofcalltree import KCacheGrind
                kg = KCacheGrind(prof)
                kg.output(open(self.setup.profile_output_filename, "w"))
        else:
            self.inner_run()