GainMedium
GainMedium combines a MeshTopology with the material and state arrays
that the ASE calculation needs.
from HASEonGPU import GainMedium
medium = GainMedium(topology=topology)
Required Fields
Assign the built-in transport fields directly on the medium. For arrays, ask the field for its primitive shape first so the code follows the topology:
medium.get("betaCells").value = np.zeros(medium.get("betaCells").expectedShape)
medium.get("betaVolume").value = np.zeros(medium.get("betaVolume").expectedShape)
medium.get("claddingCellTypes").value = np.zeros(
medium.get("claddingCellTypes").expectedShape, dtype=np.uint32
)
medium.get("refractiveIndices").value = np.asarray([2.0, 1.0, 2.0, 1.0], dtype=np.float32)
medium.get("reflectivities").value = np.zeros(
medium.get("reflectivities").expectedShape, dtype=np.float32
)
medium.get("nTot").value = 2.776e20
medium.get("crystalTFluo").value = 9.41e-4
medium.get("claddingNumber").value = 1
medium.get("claddingAbsorption").value = 5.5
The transport writer reads these named fields from the medium; examples do not construct a separate adapter object for backend input.
Property Reference
betaCellsExcited-state fraction \(\beta_i\) at topology points and z-levels. Matrix shape:
(numberOfPoints, numberOfLevels).betaVolumePrism-centered excited-state fraction \(\beta_j\) used by the ASE ray integration. Matrix shape:
(numberOfTriangles, numberOfLevels - 1).claddingCellTypesTriangle-wise cladding type index. Shape:
(numberOfTriangles,).refractiveIndicesFour refractive indices:
[bottomInside, bottomOutside, topInside, topOutside].reflectivitiesSurface reflectivity per triangle. Matrix shape:
(numberOfTriangles, 2)where column 0 is bottom and column 1 is top.nTotTotal active-ion concentration \(N_{\mathrm{tot}}\) in
cm^-3.crystalTFluoFluorescence lifetime \(\tau\).
claddingNumberCladding type selected for cladding absorption handling.
claddingAbsorptionAbsorption coefficient of the selected cladding.
Shape and Metadata Utilities
get(name) returns a property wrapper:
prop = medium.get("betaCells")
prop.name
prop.description
prop.dtype
prop.expectedShape
prop.value
prop.meta()
listProperties() returns metadata for all known physical properties:
for prop in medium.listProperties():
print(prop["name"], prop["expectedShape"], prop["isSet"])
set(name, value) validates and stores one property:
medium.set("nTot", 2.776e20)
medium.set("betaCells", np.zeros(medium.get("betaCells").expectedShape))
Arrays can be supplied either in matrix shape or flat Fortran order. Stored arrays are flattened internally for the HASEonGPU binding.
Indexing Helpers
GainMedium forwards beta-cell coordinate lookups for \(\beta_i\) to
its topology:
i, k = medium.betaCellIndexAt(x=0.0, y=0.0, z=0.0)
beta = medium.get("betaCells").value.reshape(
medium.get("betaCells").expectedShape,
order="F",
)
beta[i, k] = 0.5
medium.get("betaCells").value = beta
Convenience Dimensions
medium.numberOfPoints
medium.numberOfTriangles
medium.numberOfPrisms
medium.numberOfLevels
emptyBetaCells(fill=0.0) creates a correctly shaped beta array
\(\beta_i\):
medium.get("betaCells").value = medium.emptyBetaCells(fill=0.0)
Custom Fields
Custom fields are primarily an openPMD extension point. They let a Python workflow write additional mesh records next to the HASEonGPU records so downstream analysis tools, coupled codes, or future backends can read them. The current ASE backend ignores custom records unless a backend explicitly opts in.
GainMedium.defineField(...) creates one additional openPMD mesh record.
Choose the entity from the location of the data:
"point"for arrays shaped like(numberOfPoints, numberOfLevels)"prism"for arrays shaped like(numberOfTriangles, numberOfLevels - 1)"triangle"for arrays shaped like(numberOfTriangles,)
Always provide unit metadata when the field has a physical meaning. If omitted,
the transport writes unitSI=1.0 and
unitDimension=unitDimension.dimensionless. Unit dimensions follow the
standard seven-entry openPMD tuple.
import numpy as np
from HASEonGPU import unitDimension
temperature = np.full(medium.get("betaVolume").expectedShape, 300.0)
medium.defineField(
"temperature",
entity="prism",
values=temperature,
unit="K",
unitSI=1.0,
unitDimension=(0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0),
)
Inheritance-based declarations use the same openPMD metadata on
PrimitiveFieldSpec:
import numpy as np
from HASEonGPU import PrimitiveFieldSpec, PrismSchema
class ThermalPrism(PrismSchema):
temperature = PrimitiveFieldSpec(
"temperature",
"custom_temperature",
np.float64,
unit="K",
unitSI=1.0,
unitDimension=(0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0),
backendRequired=False,
)
medium.withPrimitiveSchema(ThermalPrism, temperature=temperature)
Predefined openPMD dimension tuples are available from unitDimension for
HASEonGPU fields and common dimensionless records.