Simulation

Simulation is the high-level time loop. It combines a GainMedium, PumpProperties, PhiASE configuration, and a time integration solver.

from HASEonGPU import Simulation, RungeKutta4

simulation = Simulation(
    gainMedium=medium,
    pump=pump,
    phiASE=phi_ase,
    timeIntegrationSolver=RungeKutta4(),
    timeStep=1e-5,
    endTime=1e-3,
)

Running

Run a fixed number of steps:

simulation.runSteps(3)

Run until a target time:

simulation.runUntil(endTime=1e-3)

If endTime was supplied to the constructor:

simulation.runUntil()

Run exactly one step and inspect the returned state:

state = simulation.step()
print(state.step, state.time, state.betaCells.shape, state.phiAse.shape)

Simulation Step Order

Each call to step() performs:

  1. One-time onInit callbacks.

  2. beforeStep callbacks.

  3. Time integration of the beta derivative \(d\beta/dt\).

  4. Pump contribution through the configured pump solver.

  5. ASE contribution through phiASE.run(...).

  6. Fluorescence decay using crystalTFluo (\(\tau\)).

  7. Clipping of updated beta values to [0, 1].

  8. betaVolume update from betaCells.

  9. Result storage and onStep callbacks.

Callbacks

onInit(callback)

Registers a callback that receives the Simulation object before the first step.

beforeStep(callback)

Registers a callback that receives the Simulation object before every step.

onStep(callback)

Registers a callback that receives the completed TimeStepState.

Example:

def print_state(state):
    print(state.step, state.time, state.betaCells.mean())

simulation.onStep(print_state)

Callbacks return values are ignored, so they are best used for logging, inspection, exporting, or controlled mutation of the simulation before a step.

Results

getResults() returns a list of TimeStepState snapshots:

results = simulation.getResults()
last = results[-1]
last.betaCells.shape
last.betaVolume.shape
last.phiAse.shape

TimeStepState fields are:

  • step: completed step index.

  • time: simulation time after the step.

  • betaCells: point and level beta values \(\beta_i\).

  • betaVolume: prism beta values \(\beta_j\) used by ASE.

  • phiAse: ASE flux values \(\Phi_i\), or None if unavailable.

  • dndtAse: ASE derivative contribution to \(d\beta/dt\).

  • dndtPump: pump derivative contribution to \(d\beta/dt\).

  • aseResult: raw lower-level ASE result object.

Properties

simulation.time
simulation.stepIndex

time and stepIndex expose the current simulation clock and completed step count.

Spectral Properties Resolution

Simulation requires spectral properties such as cross sections and emission spectra. These properties may be defined at different levels, for example globally for the whole simulation or locally for individual objects.

When multiple definitions are available, the simulation resolves them using a fixed priority order. More specific definitions override more general ones. This determines which spectral data is used for each object during the simulation.

  1. Simulation.crossSections

  2. phiASE.spectralProperties

  3. phiASE.crossSections

  4. pump.spectralProperties

  5. pump.crossSections

The resolved spectra are also written back to phiASE if needed.

Time Integration

timeIntegrationSolver must provide:

step(rhs, betaCells, time, timeStep)

Built-in solvers are documented in Utilities.

Beta Volume Mapping

Simulation updates betaVolume (\(\beta_j\)) from betaCells (\(\beta_i\)) after each step using LegacyGridDataBetaVolumeMapper. The mapper interpolates beta values from topology points and z-levels to prism centers. It requires scipy.

updateTerminalLevel

By default updateTerminalLevel=True and every z-level is updated. If it is set to False, the terminal level is preserved while the other levels are advanced.