Python interface#
This section describes the Python user interface of Mulder. The user interface is organised in sub-topics, Geometry, Materials, Modules, Physics, States, Simulation and Pictures, as described below. Moreover, Mulder exhibits some package-level data, as outlined in the Configuration section.
Geometry interface#
To represent an Earth-like geometry, typically described by a Digital Elevation
Model (DEM), Mulder provides a dedicated EarthGeometry
object. Alternatively, a Calzone (Geant4) geometry can be imported as a
LocalGeometry object. Other use cases might be implemented
as an external Module (using Mulder’s C interface). Mulder
geometry objects rely on a common model, inherited from Pumas [Nie22],
which is discussed in the Geometry section.
- class mulder.EarthGeometry#
A stratified Earth geometry.
This class represents a stratified section of the Earth. The strates (or
Layers) form distinct propagation media that are assumed to be uniform in composition and density. They are delimited vertically, typically by aGridof elevation values, forming a Digital Elevation Model (DEM).Note
Mulder uses Turtle’s algorithm [NBCM20] to efficiently navigate through
EarthGeometryobjects.- __new__(*layers)#
Creates a new Earth geometry.
The layers are provided in index order, i.e. the first layer has index
0and is thus the bottom strate. Each individual layer argument may be either an explicitLayerobject, or data-like objects coercing to the latter. For instance, the following two syntaxes lead to the same geometry.>>> geometry = mulder.EarthGeometry( ... mulder.Layer("dem.asc", 0.0), ... mulder.Layer(-100.0) ... )
>>> geometry = mulder.EarthGeometry( ... ("dem.asc", 0.0), ... -100.0 ... )
Geometry methods
Note
The geometry methods below use the Coordinates interface to specify the coordinates of interest.
- locate(position=None, /, *, notify=None, **kwargs)#
Locates point(s) within the Earth geometry.
The method returns the layer index(es) that correspond to the input position(s). For instance,
>>> layer = geometry.locate(latitude=45, altitude=-5.0)
- scan(coordinates=None, /, *, notify=None, output=None, **kwargs)#
Performs a scan of the Earth geometry.
The output argument determines the returned data. The possible values are
"grammage"(i.e., \(\int{\rho(s) ds}\), a.k.a. opacity in the context of muography),"intersections"and"thickness"(which is the default setting). For instance, the following returns anarraycontaining the thicknesses of the layers along the line(s) of sight specified by the input coordinates, as>>> thickness = geometry.scan(latitude=45, elevation=10) >>> thickness[0] 3.0
If output is set to
"intersections", then, for each input coordinate, this method returns anarraycontaining the successive tracing intersections, as obtained per thetrace()method.
- trace(coordinates=None, /, *, ignore=None, notify=None, **kwargs)#
Performs a tracing step of the Earth geometry.
The method returns a structured
arraydescribing the first intersection(s) along the line(s) of sight specified by the input coordinates. For instance,>>> intersection = geometry.trace(latitude=45, elevation=10) >>> intersection["distance"] 3.0
During the tracing process, specific layers can be excluded by providing their indices as the optional ignore argument.
Attributes
Note
EarthGeometryobjects are immutable, i.e. their structure cannot be modified. However, thedensityandmaterialoflayersis mutable.- layers#
The Earth geometry layers.
The first layer (of index
0) is the bottom strate, while the last layer is the top-most strate. The latter can be accessed as>>> top = geometry.layers[-1]
- zlim#
The Earth geometry limits along the z-coordinate.
- class mulder.Grid#
This class represents a parametric surface, \(z = f(x, y)\), described by a regularly spaced
Gridof elevation values, \(z_{ij} = f(x_j, y_i)\), forming a Digital Elevation Model (DEM).The elevation values, \(z_{ij}\), of a
Gridobject may be offset by a constant value using the+and-operators. For example, the following will create a new grid offset by100.0metres w.r.t. the initial one.>>> new_grid = initial_grid + 100.0
Tip
The offsetting of a grid creates a reference to the data of the initial grid, i.e. data is not duplicated.
- __new__(data, /, *, xlim=None, ylim=None, crs=None)#
Creates a new grid.
The data argument may refer to:
A file containing a DEM (see Table 1 for supported file formats).
A folder containing the tiles of a Global Digital Elevation Model (GDEM), such as SRTMGL1.003.
A 2D array containing the \(z_{ij}\) values in row-major order.
In the latter case, the xlim and ylim arguments must specify the DEM limits along the \(x\) and \(y\)-axes.
Depending on the data argument, a Coordinate Reference System (CRS) may be specified (by providing its EPSG code). See Table 2 for a list of supported crs values. By default, the WGS84 / GPS system is assumed.
For instance, the following loads elevation data stored in ASCII Grid format using UTM 31N coordinates, i.e. EPSG:32631.
>>> grid = mulder.Grid("dem.asc", crs=32631)
Table 1 Supported file formats.# Description
Extension
.asc.tif.grd.hgtTable 2 Supported Coordinate Reference Systems.# Description
EPSG code(s)
NTF / Lambert I-IV
27571-27574
RGF93 / Lambert 93
2154
WGS84 / GPS
4326
WGS84 / UTM 1-60 N
32601-32660
WGS84 / UTM 1-60 S
32701-32760
Methods
- gradient(x_or_xy, y=None, /, *, notify=None)#
Computes the elevation gradient(s) at grid point(s).
This method returns the gradient w.r.t. the \(x\) and \(y\) coordinates. The interface is the same as the
Grid.z()method. Please refer to the latter for a description of the arguments.
- z(x_or_xy, y=None, /, *, notify=None)#
Computes the elevation value(s) at grid point(s).
This method is vectorised. It accepts either a sequence of \((x_k, y_k)\) values as the first argument, or two sequences of \(x_j\) and \(y_i\) values as the first and second arguments. In the latter case, the method returns the \(z_{ij}\) values corresponding to the outer product \((x_j, y_i)\). For instance, the following returns a 2D array of elevation values, z, with shape
(41, 21).>>> x, y = np.linspace(-1, 1, 21), np.linspace(-2, 2, 41) >>> z = grid.z(x, y)
Attributes
Note
Gridinstances are immutable.- crs#
Coordinate Reference System.
The grid Coordinate Reference System (CRS) is encoded according to the EPSG standard. For example,
>>> grid.crs 32631
- xlim#
Grid limits along the x-coordinate.
- ylim#
Grid limits along the y-coordinate.
- zlim#
Grid limits along the z-coordinate.
- class mulder.Layer#
A layer (or strate) of an Earth geometry.
This class represents a layer (or strate) of an
EarthGeometry, considered to be uniform in composition and density. A layer is delimited by a top surface, typically described by one or moreGridsof elevation values. The bottom of a layer is determined by the top of its underlying layer within theEarthGeometry.- __new__(*data, density=None, description=None, material=None)#
Creates a new layer.
The data argument determines the top of the layer. It must be akin to a
Gridobject. Alternatively, afloatvalue can be provided to specify a flat topography. Multiple data can be provided to specify successive fallback models. For example, the following creates a new layer whose top surface is defined by two data sets, as>>> layer = mulder.Layer("dem.asc", 0.0)
The corresponding top surface matches the Digital Elevation Model (DEM) from the file
dem.ascwithin its domain of definition, but falls back to a constant elevation value of0outside this domain.See the layer attributes below for the meaning of the optional
density,descriptionandmaterialarguments.
Methods
- altitude(latitude_or_latlon, longitude=None, /, *, frame=None, notify=None)#
Computes the layer top altitude(s) at coordinate(s).
This method is vectorised. It accepts either a sequence of \((\phi_k, \lambda_k)\) values as the first argument, where \(\phi\) denotes the latitude and \(\lambda\) the longitude, or two sequences of \(\phi_i\) and \(\lambda_j\) values as the first and second arguments. In the latter case, the method returns the \(z_{ij}\) values corresponding to the outer product \((\lambda_j, \phi_i)\). For instance, the following returns a 2D array of altitude values with shape
(181, 361).>>> lat, lon = np.linspace(-90, 90, 181), np.linspace(-180, 180, 361) >>> altitudes = layer.altitude(lat, lon)
- normal(latitude_or_latlon, longitude=None, /, *, frame=None, notify=None)#
Computes the layer top normal(s) at coordinate(s).
This method returns the normal to the top surface at the latitude (\(\phi\)) and longitude (\(\lambda\)) coordinates. The interface is the same as the
Layer.altitude()method. Please refer to the latter for a description of the arguments.The optional frame argument specifies the coordinates system (as a
LocalFrame) in which the normal should be expressed. If this argument is omitted, geocentric (ECEF) coordinates will be used.
Attributes
- data#
The layer top elevation data.
Note
This attribute is immutable.
- density#
The layer bulk density.
The bulk density is expressed in \(\mathrm{kg}/\mathrm{m}^3\). If
None, then the material default density is assumed.
- description#
An optional description.
- material#
The layer constitutive material.
This attribute is the name of the material. For instance, the following changes the layer material to water.
>>> layer.material = "Water"
- class mulder.LocalFrame#
An Earth-local reference-frame.
This class specifies a Local-Tangent-Plane (LTP) reference frame on the Earth. Optionnaly, the frame can be inclined (w.r.t. the vertical) or declined (w.r.t. the geographic north).
Note
LocalFrameinstances are immutable.- __new__(coordinates=None, /, **kwargs)#
Creates a new Earth-local reference-frame.
The coordinates argument specifies the origin position and the y-axis direction, using the Coordinates interface. For example, the following defines a local frame close to Clermont-Ferrand, France.
>>> frame = mulder.LocalFrame(latitude=45.8, longitude=3.1)
If no direction is specified, then local frames are East-North-Upward (ENU) oriented by default.
- camera(resolution=None, /, *, focal=None, fov=None, ratio=None)#
Spawns a new camera.
See the
Cameraobject documentation for further details.Note
The focal and fov arguments cannot be specified simultaneously since these two quantities are directly related.
- looking_at(position=None, /, *, skew=None, **kwargs)#
Returns a rotated local frame.
The position argument specifies the target point using the Position interface. For example, the following returns a local frame oriented along the x-axis of the initial frame.
>>> frame1 = frame0.looking_at(position=(1, 0, 0))
- transform(q, /, *, destination, mode)#
Transforms point(s) or vector(s) to another local frame.
The quantity, q, is transformed from the self
LocalFrameto the destination one. The mode parameter specifies the nature of q (i.e.,"point"or"vector"). For example, the following computes the coordinates, inframe1, of the \(\vec{e}_x\) basis vector offrame0.>>> ex = frame0.transform((1, 0, 0), destination=frame1, mode="vector")
- translated(v, /)#
Returns a translated local frame.
The translation vector v is expressed in the local coordinates of the initial frame. For instance, the following returns a frame translated by 1 meter along the x-axis of the initial frame.
>>> frame1 = frame0.translated((1, 0, 0))
Position attributes
- altitude#
The altitude coordinate of the frame origin, in m.
- latitude#
The latitude coordinate of the frame origin, in deg.
- longitude#
The longitude coordinate of the frame origin, in deg.
Direction attributes
Note
The
azimuthandelevationattributes refer to the y-axis direction. The skew angle (a.k.a. roll angle) is a rotation around the transformed y-axis.- azimuth#
The frame azimuth angle (w.r.t. the geographic north), in deg.
- elevation#
The frame elevation angle (w.r.t. the local vertical), in deg.
- skew#
The frame skew angle (a.k.a. roll angle), in deg.
- class mulder.LocalGeometry#
A local geometry.
This class represents a local geometry on the Earth, w.r.t. a
LocalFrame. Local geometries can be created by importing a Calzone geometry. Alternatively, they might be implemented using an external software, typically in C/C++, wrapped within amulder.Module.- __new__(data, /, *, frame=None)#
The data argument may be a path-string pointing to a
Modulefile or to a Calzone geometry file. Alternatively, one might provide acalzone.Geometryobject as data argument. For instance, the following loads a local geometry from a Calzone geometry file.>>> geometry = mulder.LocalGeometry("geometry.toml")
The optional frame argument specifies the origin and orientation of the local geometry as a
LocalFrameobject.
Geometry methods
- locate(position=None, /, *, notify=None, **kwargs)#
Locates point(s) within the local geometry.
The method returns the media index(es) that correspond to the input position(s). For instance,
>>> media = geometry.locate(position=[0, 0, 1])
- scan(coordinates=None, /, *, notify=None, output=None, **kwargs)#
Performs a scan of the local geometry.
The output argument determines the returned data. The possible values are
"grammage"(i.e., \(\int{\rho(s) ds}\), a.k.a. opacity in the context of muography),"intersections"and"thickness"(which is the default setting). For instance, the following returns anarraycontaining the thicknesses of the media along the line(s) of sight specified by the input coordinates, as>>> thickness = geometry.scan(position=[0, 0, 1], direction=[0, 0, -1]) >>> thickness[0] 1.0
If output is set to
"intersections", then, for each input coordinate, this method returns anarraycontaining the successive tracing intersections, as obtained per thetrace()method.
- trace(coordinates=None, /, *, ignore=None, notify=None, **kwargs)#
Performs a tracing step of the local geometry.
The method returns a structured
arraydescribing the first intersection(s) along the line(s) of sight specified by the input coordinates. For instance,>>> intersection = geometry.trace(position=[0, 0, 1], direction=[0, 0, -1]) >>> intersection["distance"] 1.0
During the tracing process, specific media can be excluded by providing their indices as the optional ignore argument.
Attributes
- frame#
The geometry reference frame.
The geometry reference frame is mutable. For instance,
>>> geometry.frame = mulder.LocalFrame(altitude=10.0)
- media#
The geometry media.
The geometry media form an immutable sequence. A medium is identified by its index within this sequence. For instance, the following returns the first medium
>>> first = geometry.media[0]
- class mulder.Medium#
A medium of a local geometry.
This class represents a medium of a
LocalGeometry, considered to be uniform in composition and density.- normal(position=None, /, *, notify=None, **kwargs)#
Computes the surface normal(s).
Attributes
- density#
The medium bulk density.
The bulk density is expressed in \(\mathrm{kg}/\mathrm{m}^3\). If
None, then the material default density is assumed.
- description#
An optional description.
- material#
The medium constitutive material.
This attribute is the name of the material. For instance, the following changes the medium material to water.
>>> medium.material = "Water"
Materials interface#
Mulder makes a distinction between base Materials and Composite
materials. A base Material is a microscopic
mixture of atomic Elements. A
Composite material, by contrast, is a macroscopic
mixture of base Materials, typically a
rock composed of various minerals.
Note
The stopping-power of a Composite material
slightly differs from that of a base Material
with the same composition, due to the density effect in ionisation loss.
A material (atomic element) is uniquely identified by its name (atomic symbol),
which maps to a concrete definition, e.g. a
Material (Element).
The mapping may be lazy, i.e. delayed until usage. Once a material (element)
definition has been established, it cannot be modified or removed.
Note
The resolution of unmapped materials (elements) is done in the following order.
- class mulder.materials.Composite#
This class represents a macroscopic mixture of
Materials.Compositeobjects use the mapping protocol to expose their components’ mass fractions, which are mutable. For example>>> composite["Water"] = 0.1
It is not possible to add or remove a constitutive material once the composite has been mapped. However, a specific material may be disabled by setting its mass fraction to zero.
- __new__(name, /)#
Gets a composite definition.
Returns the definition of the composite matching name. For instance,
>>> composite = materials.Composite("HumidRock")
- all()#
Returns all currently mapped composites.
The composites are returned as a
dictobject mapping names to definitions.
- define(name, /, *, composition)#
Defines a composite material.
Note
This method explictly maps the material name to the provided composite definition.
The composite is defined by specifying its composition, for instance as,
>>> humid_rock = materials.Composite.define( ... "HumidRock", ... composition=("Rock", "Water"), ... )
The mass fractions may also be specified when defining the composite, for instance as
>>> humid_rock = materials.Composite.define( ... "HumidRock", ... composition={"Rock": 0.95, "Water": 0.05}, ... )
Attributes
Note
Compositeinstances are immutable appart from their components’ mass fractions.- composition#
The composite content.
The composite content is returned as a
tuple. For example>>> humid_rock.composition ('Rock', 'Water')
The corresponding mass fractions may be accessed using the mapping protocol, as
>>> humid_rock["Water"] 0.05
- density#
The composite density, in kg/m3.
Note
The composite density depends on the mass fractions of its constitutive materials.
- class mulder.materials.Element#
This class represents an atomic element, which may be a specific isotope or a mixture of isotopes.
Tip
Mulder provides default definitions for atomic elements from
H,D(\(Z=1\)) toOg(\(Z=118\)) according to the PDG. Furthermore, Mulder provides a fictitiousRk(\(Z=11, A=22\)) element to represent standard rock.- __new__(symbol, /)#
Gets an atomic element definition.
Returns the definition of the atomic element matching symbol. For instance,
>>> H = materials.Element("H")
- all()#
Returns all currently mapped elements.
The elements are returned as a
dictobject mapping the atomic elements symbols to their definitions.
- define(symbol, /, *, Z, A, I=None)#
Defines a new atomic element.
Note
This method explictly maps the element symbol to the provided element definition.
If the Mean Excitation Energy (I) is omitted, a default value is used depending on Z. For example,
>>> U_238 = materials.Element.define("U-238", Z=92, A=238.0508)
Attributes
Note
Elementinstances are immutable.- A#
The element mass number, in g/mol.
- I#
The element Mean Excitation Energy, in GeV.
- Z#
The element atomic number.
- class mulder.materials.Material#
This class represents a homogeneous material, at the microscopic scale. A
Materialobject may be composed of a single atomicElement(e.g., C), a molecule (e.g., H2O) or be a mixture (e.g., air). In addition to the atomiccomposition, the material structure is essentially summarised by itsdensityand its mean excitation energy (I).Tip
Mulder provides default definitions for the
Air,RockandWatermaterials.- __new__(name, /)#
Gets a material definition.
Returns the definition of the material matching name. For instance,
>>> rock = materials.Material("Rock")
- all()#
Returns all currently mapped materials.
The materials are returned as a
dictobject mapping names to definitions.
- define(name, /, *, composition, density, I=None)#
Note
This method explictly maps the material name to the provided material definition.
The composition argument may be a
str, specifying the material chemical composition, as>>> ice = materials.Material.define("Ice", composition="H2O", density=0.92E+03)
Alternatively, the composition argument may be akin to a
dictmapping atomic elements or other materials to mass fractions. For example, as>>> moist_air = materials.Material.define( ... "MoistAir", ... composition={"Air": 0.99, "Water": 0.01}, ... density=1.2 ... )
See the material attributes below for a description of the density and I arguments.
Attributes
Note
Materialinstances are immutable.- composition#
The material mass composition.
The atomic mass composition is returned as a
tuple. For example>>> moist_air.composition (('Ar', 0.0126987...), ..., ('O', 0.2383443...))
- density#
The material density, in kg/m3.
- mulder.materials.dump(path, *materials)#
Dump material definitions.
If the materials arguments are ommited, then all currently mapped material definitions are dumped to a TOML file, for instance as
>>> materials.dump("materials.toml")
Alternatively, one may explicit the material definitions to dump, for example as
>>> materials.dump("materials.toml", "Ice", "MoistAir", "HumidRock")
- mulder.materials.load(path, /)#
Load material definitions.
The definition file must be in TOML format. For example, the following
materials.tomlfile defines twoMaterials(IceandMoistAir) and oneComposite(HumidRock).[Ice] composition = "H2O" density = 0.92E+03 # kg/m3 [MoistAir] composition = { Air = 0.99, Water = 0.01 } # mass fractions density = 1.2 # kg/m3 [HumidRock] composition = [ "Rock", "Water" ]
The corresponding material definitions are loaded as
>>> materials.load("materials.toml")
Module interface#
External software may be interfaced with Mulder as external modules. For further information, please refer to the External modules section.
- class mulder.Module#
This class provides an interface to an external module, typically implemented in C/C++. External modules may extend Mulder functionalities with new materials and geometries.
- __new__(path, /)#
Loads a Module.
The path argument must refer to a shared library containing the module implementation. For instance, on a Linux system,
>>> module = mulder.Module("module.so")
Methods
- element(symbol, /)#
Fetches a module atomic element.
This method explictly maps the element symbol to its module definition. For example,
>>> H = module.element("G4_H")
- geometry(*, frame=None)#
Creates an external geometry.
The external geometry is returned as a
LocalGeometryobject, for example as,>>> geometry = module.geometry()
Optionally, a
LocalFramemay be specified using the frame named argument.
- material(name, /)#
Fetches a module material.
This method explictly maps the material name to its module definition. For example,
>>> air = module.material("G4_AIR")
Attributes
Note
Moduleattributes are immutable.- path#
The module location.
The absolute path to the shared library containing the module implementation. This path also serves as a unique identifier for the module during runtime.
- ptr#
Pointer to the C interface.
A
ctypes.c_void_ppointing to the initialised module, i.e. to thestruct mulder_moduleobject obtained upon calling themulder_initialise()entry point function.
Physics interface#
Mulder builds over the Pumas transport engine, the physics implementation of
which is described in detail in [Nie22]. In order to improve performance, some
key physical properties are pre-computed and later interpolated at runtime, e.g.
cross-sections, stopping-powers, etc. This process can be triggered manually
using the compile() method of a
Physics instance, which translates a set of
Material and
Composite definitions into
CompiledMaterials, providing access to the
tabulated physical properties.
Note
Since their computation can be time consuming, material tables related to a
specific set of materials and Physics settings are
cached. See the DEFAULT_CACHE entry for information on controlling
the cache location.
Tip
Fluxmeters seamlessly manage the generation of
material tables, negating the need for any explicit compilation.
- class mulder.CompiledMaterial#
This class acts as a proxy for the material tables relating to a specific material. The physical properties can be accessed via vectorised class methods. For example as,
>>> energy = np.geomspace(1E-02, 1E+03, 101) >>> stopping_power = compiled_material.stopping_power(energy)
Note
The
CompiledMaterialclass cannot be instantiated directly; it must be generated using thePhysics.compile()method instead.Methods
- cross_section(energy, /, *, notify=None)#
Returns the macroscopic cross-section.
The macroscopic cross-section, expressed in \(\mathrm{m}^{-1}\), is restricted to hard collisions with a fractionnal energy loss larger than the physics
cutoff. Collisions with a smaller energy loss are included in the continuous energy loss given by thestopping_power()method.Note
The hard elastic collisions are not included in the macroscopic cross-section but in the elastic mean free path given by the
elastic_scattering()method.
- elastic_scattering(energy, /, *, notify=None)#
Returns the muon elastic scattering properties.
This method returns the mean free path, in metres, restricted to hard elastic collisions and the corresponding cutoff angle, in deg. The cutoff angle is expressed in the center of mass frame of the collision. It is set according to the physics
elastic_ratiofollowing Fernandez-Varea et al. [FMBS93].Note
Soft elastic collisions are taken into account in the multiple scattering (see the
transport_path()method).
- inverse_range(range, /, *, mode=None, notify=None)#
Returns the inverse of the muon CSDA range.
This method returns the inverse of the CSDA range, i.e. the required muon kinetic energy, in GeV, for a given range, expressed in metres. See the
range()method for further details.
- magnetic_gyration(energy, /, *, mode=None, notify=None)#
Returns the magnetic gyration coefficient.
This method returns the magnetic gyration coefficient, \(g\), over the total muon range, assuming continuous energy loss. The gyration coefficient is defined as
\[g = \frac{\theta}{B_\perp} ,\]where \(B_\perp\) is the magnetic field transverse to the muon direction, and \(\theta\) the resulting rotation angle. The returned gyration coefficient is expressed in deg / T.
- proper_time(energy, /, *, mode=None, notify=None)#
Returns the muon proper time.
This method returns the ellapsed proper time of a particle over its total range, in seconds. Continuous energy loss is assumed.
- range(energy, /, *, mode=None, notify=None)#
Returns the muon CSDA range.
The CSDA range is expressed in metres. See the
stopping_power()method for the corresponding continuous energy loss.Note
In
mixedordiscretemodes, the range does not include hard collisions.
- stopping_power(energy, /, *, mode=None, notify=None)#
Returns the material stopping-power.
The material stopping-power is expressed in \(\mathrm{GeV}/\mathrm{m}\). See the
range()method for the corresponding CSDA range.Note
In
mixedordiscretemodes, the stopping power does not include hard collisions.
- transport_path(energy, /, *, mode=None, notify=None)#
Returns the transport mean free path.
The transport mean free path, expressed in metres, is restricted to soft collisions, including both elastic and inelastic processes.
Note
The transport m.f.p., \(\lambda\), is related to the standard deviation of the multiple scattering angle as \(\sigma_\theta^2 = s / (2 \lambda)\), where \(s\) is the travelled distance.
Attributes
- definition#
The material definition.
This attribute is an instance of
CompositeorMaterial, depending on the type of material.
- name#
The material name.
- class mulder.Physics#
This class provides access to configurable Pumas settings relevant to muon transport physics, as mutable attributes. For further details, please refer to [Nie22]. In addition, the
Physicsclass provides an interface for generating material tables from material definitions, using thecompile()method.- __new__(**kwargs)#
Creates a Physics context.
Configuration settings can be provided as keyword arguments (kwargs). See the class attributes below for a list of possible parameters. For example,
>>> physics = mulder.Physics(cutoff=5E-02)
Methods
- compile(*materials, notify=None)#
Compiles material definitions to physics tables.
If the materials arguments are ommited, then all currently defined materials are compiled. The returned
CompiledMaterialscan be extracted to adict, for instance as>>> compiled = { m.name: m for m in physics.compile() }
Alternatively, one may explicit the materials to compile, for example as
>>> ice, rock = physics.compile("Ice", "Rock")
Attributes
- bremsstrahlung#
The Bremsstrahlung model for muon energy losses.
The possible values for bremsstralung models are summarised in Table 3 below, the default setting is
"SSR19".
- cutoff#
The cutoff between hard and soft energy losses.
Relative cutoff between soft and hard energy losses. Setting a null or negative value results in the default cutoff value to be used i.e. 5% which is a good compromise between speed and accuracy for transporting a continuous muon spectrumm, see e.g. Sokalski et al. [SBK01].
Warning
Cutoff values lower than 1% are not supported.
- elastic_ratio#
The hard to soft ratio for elastic collisions.
Ratio of the mean free path for hard elastic events to the smallest of the transport mean free path or CSDA range. The lower the ratio the more detailed the simulation of elastic scattering, see e.g. Fernandez-Varea et al. [FMBS93]. Setting a null or negative value results in the default ratio to be used i.e. 5%.
- pair_production#
The e+e- pair-production model for muon energy losses.
The possible values for pair-production models are summarised in Table 4 below, the default setting is
"SSR19".
- photonuclear#
The photonuclear model for muon energy losses.
The possible values for photonuclear interaction models are summarised in Table 5 below, the default setting is
"DRSS01".Table 5 Available photonuclear interaction models.# Model
Reference
"BBKS03"Bezrukov, Bugaev, Sov. J. Nucl. Phys. 33 (1981), 635, with improved photon-nucleon cross-section according to Kokoulin and hard component from Bugaev and Shlepin.
"BM02"Butkevich and Mikheyev, Soviet Journal of Experimental and Theoretical Physics 95 (2002) 11.
"DRSS01"Dutta, Reno, Sarcevic and Seckel, Phys.Rev. D63 (2001) 094020.
States interface#
A Mulder state is a set of variables used to characterise a flux of muons. Typically, a state specifies a view point (position and direction of observation) together with the kinetic energy of the observed muons.
Tip
State variables may be vectorised, e.g. to represent a collection of muons, or a spectrum. Mulder follows a straightforward broadcasting rule that requires variables to be either scalar or to share the same size, regardless of their array shape.
Mulder considers two different representations of a set of states,
GeographicStates and LocalStates,
differing by their coordinate system. GeographicStates
represent the position and direction of observation using geographic-like
variables (e.g. latitude, longitude), while LocalStates use
Cartesian coordinates w.r.t. a LocalFrame. The
correspondence between the two representations is outlined in
Table 6 below. Conversion methods (e.g.
to_geographic(),
to_local()) can be used to transform between
the two representations.
Geographic representation |
Local representation |
|---|---|
Note
The direction of observation variable(s) specifies the opposite of the muon propagation direction, in both the Geographic and Local representations.
Note
The pid variable is optional. It categorises a state as a muon
(pid = 13) or as an anti-muon (pid = -13). If ommitted,
each state is regarded as a superposition of muons and anti-muons.
Tip
State variables are stored internally as NumPy structured arrays accessible via the array
attribute. For the sake of convenience, shape related attributes
(ndim,
shape,
size) are also forwarded.
States objects are used as input to Mulder functions, for instance as follows
>>> states = mulder.GeographicStates(
... latitude = 45.0,
... energy = np.geomspace(1E-02, 1E+04, 61)
... )
>>> result = some_state_function(states)
Alternatively, state variables can be provided directly as named arguments. For instance, the following syntax produces the same result as the previous example.
>>> result = some_state_function(
... latitude = 45.0,
... energy = np.geomspace(1E-02, 1E+04, 61)
... )
Some Mulder functions use only a subset of state variables, thus defining sub-interfaces. Functions that require only position (position and direction) variables are said to follow the Position interface (Coordinates interface). These functions will also accept states objects as positional arguments, but only position (position and direction) variables as named arguments.
- class mulder.GeographicStates#
A geographic representation of Mulder states.
- __new__(states=None, /, **kwargs)#
Creates state(s) using geographic coordinates.
This class method uses the States interface. For instance,
>>> states = mulder.GeographicStates( ... latitude = 45, ... energy = np.geomspace(1E-02, 1E+04, 61) ... )
Coordinates methods
- from_local(states, /)#
Creates geographic states from local ones.
- to_local(frame=None, /)#
Converts the geographic states to local ones.
Array methods
Note
Depending on the tagged argument, the array methods described below return tagged muon or anti-muon states, or untagged ones (i.e. a superposition of muons and anti-muons).
- dtype(*, tagged=False)#
Returns the corresponding array dtype.
- empty(shape=None, /, *, tagged=False)#
Returns uninitialised geographic states.
- full(shape=None, /, fill_value=None, **kwargs)#
Returns a collection of identical geographic states.
- from_array(array, /, *, copy=True)#
Creates geographic states from a Numpy array.
The input NumPy array must be of
GeographicStates.dtype. If copy isFalse, the returnedGeographicStatesobject refers to the input array.
- zeros(shape=None, /, *, tagged=False)#
Returns zeroed geographic states.
Coordinates attributes
Note
The direction of observation is the opposite of the muon propagation direction.
Note
The
azimuthandelevationangles refer toLocalFrames, the origins of which are defined by thelatitude,longitudeandaltitudeattributes.- altitude#
The altitude coordinate, in m.
- azimuth#
The azimuth angle of observation, in deg.
- elevation#
The elevation angle of observation, in deg.
- latitude#
The latitude coordinate, in deg.
- longitude#
The longitude coordinate, in deg.
Common state attributes
- energy#
The kinetic energy, in GeV.
- pid#
The PDG particle identifier.
For untagged states this attribute is immutably
None.
- weight#
The Monte Carlo weight.
Array attributes
- array#
The underlying NumPy array.
- ndim#
The geographic states’ array dimension.
- shape#
The geographic states’ array shape.
- size#
The total number of geographic states.
- class mulder.LocalStates#
A local representation of Mulder states.
- __new__(states=None, /, **kwargs)#
Creates state(s) using local coordinates.
This class method uses the States interface. For instance,
>>> states = mulder.LocalStates( ... direction = (0, 0, 1), ... energy = np.geomspace(1E-02, 1E+04, 61) ... )
Coordinates methods
- from_geographic(*, frame=None)#
Creates local states from geographic ones.
- to_geographic()#
Converts the local states to geographic ones.
- transform(destination)#
Transforms to another local frame.
Array methods
Note
Depending on the tagged argument, the array methods described below return tagged muon or anti-muon states, or untagged ones (i.e. a superposition of muons and anti-muons).
- dtype(*, tagged=False)#
Returns the corresponding array dtype.
- empty(shape=None, /, *, tagged=False)#
Returns uninitialised local states.
- full(shape=None, /, fill_value=None, **kwargs)#
Returns a collection of identical local states.
- from_array(array, /, *, copy=True, frame=None)#
Creates local states from a Numpy array.
The input NumPy array must be of
LocalStates.dtype. If copy isFalse, the returnedLocalStatesobject refers to the input array.
- zeros(shape=None, /, *, tagged=False)#
Returns zeroed local states.
Coordinates attributes
- frame#
The coordinates local frame.
- position#
The local position, in m.
- direction#
The local direction of observation.
Note
The direction of observation is the opposite of the muon propagation direction.
Common state attributes
- energy#
The kinetic energy, in GeV.
- pid#
The PDG particle identifier.
For untagged states this attribute is immutably
None.
- weight#
The Monte Carlo weight.
Array attributes
- array#
The underlying NumPy array.
- ndim#
The local states’ array dimension.
- shape#
The local states’ array shape.
- size#
The total number of local states.
Simulation interface#
A Mulder simulation is managed using a Fluxmeter object. For
basic use cases, one might simply invoke the flux()
methods which returns the muon flux for input observation states, depending on the Fluxmeter configuration
(atmosphere, geometry, reference,
etc.). For more advanced usage, please refer to the flux computation section.
- class mulder.Atmosphere#
An atmospheric medium.
This class manages the properties of the atmosphere medium. The atmosphere is assumed to be homogeneous in composition, but with a density that varies vertically.
- __new__(model=None, /, *, material=None)#
Creates a new atmospheric medium.
The model argument specifies the vertical density profile, which is provided as an \(N \times 2\) array mapped as \([(z_0, \rho_0), \ldots, (z_{N-1}, \rho_{N-1})]\) with altitudes (\(z\)) in meters and densities (\(\rho\)) in \(\mathrm{kg} / \mathrm{m}^3\). For instance,
>>> atmosphere = mulder.Atmosphere(( ... ( 0, 1.225E+00), ... ( 1_000, 4.135E-01), ... (30_000, 1.841E-02), ... (70_000, 8.283E-05), ... ))
Note
The provided altitude values (\(z\)) should be strictly increasing, and the density values (\(\rho\)) must be strictly positive.
Alternatively, a predefined model can be specified, e.g. as
>>> atmosphere = mulder.Atmosphere("midlatitude-summer")
See the
modelsclass attribute for a list of predefined density models.By default, the atmosphere is composed of
"Air". This can be overridden using the optional material argument, for examples as follows>>> atmosphere = mulder.Atmosphere(material="SaturatedAir")
See the Materials interface for information on defining custom materials.
- density(altitude, /)#
Computes the density value(s) at the specified altitude(s).
This method is vectorised. It can accomodate a scalar altitude input or an array of altitude values. For instance,
>>> densities = atmosphere.density(np.linspace(0E+00, 1E+05, 10001))
Attributes
- material#
The constitutive material.
This is a mutable attribute. For instance, the following changes the atmosphere material
>>> atmosphere.material = "SaturatedAir"
See the Materials interface for information on defining custom materials.
- model#
The density model.
This is an immutable attribute containing a copy of the density model used when the atmospheric medium was defined.
Class attributes
- class mulder.EarthMagnet#
A snapshot of the geomagnetic field.
This class provides an interface to a geomagnetic model, parametrised by spherical harmonics. The default model used by Mulder is IGRF14.
- __new__(model=None, /, *, date=None)#
Creates a new snapshot of the geomagnetic field.
If provided, the model argument should point to a
*.COFfile containing the geomagnetic model coefficients.The optional date argument allows the user to specify the date of the snapshot, as a
datetime.dateobject, or as an ISO 8601-formatted string. For instance,>>> from datetime import date >>> magnet = mulder.EarthMagnet(date=date.today())
or
>>> magnet = mulder.EarthMagnet(date="1978-08-16")
- field(position=None, /, *, notify=None, **kwargs)#
Computes the geomagnetic field value(s) at the specified position(s).
This method uses the Position interface for specifying the position(s) of interest. For instance, using geographic coordinates
>>> field = magnet.field(latitude=45, longitude=3)
The returned field is expressed in Tesla (T) units, with the coordinates frame depending on the input position. For geographic positions, ENU coordinates are returned. For local positions, the field is returned in the local frame of the input positions.
Attributes
Note
EarthMagnetinstances are immutable.- date#
The snapshot date.
- model#
The model name.
- zlim#
The model altitude limits, in m.
- class mulder.Fluxmeter#
A muon fluxmeter.
This class provides a high-level interface for computing alterations in the flux of atmospheric muons, due to
geometricalfeatures, w.r.t. to an open-skyreferencemodel. For basic use cases one might simply use theflux()method with default settings. For more advanced usage, please refer to the flux computation section.- __new__(*layers, **kwargs)#
Creates a new fluxmeter.
The layers arguments may specify an
EarthGeometry. For instance, the following creates a meter with a 2-layers geometry.>>> meter = mulder.Fluxmeter( ... ("dem.asc", 0.0), ... -100.0 ... )
Alternatively, the geometry may be explicitly specified as a named argument. For instance, the following creates a meter with a
LocalGeometryloaded from a file.>>> meter = mulder.Fluxmeter(geometry="geometry.toml")
Other attributes (see below) may be specified as named arguments, as well. For instance,
>>> meter = mulder.Fluxmeter( ... atmosphere = "midlatitude-winter", ... date = "2025-12-25", # For geomagnetic field. ... mode = "mixed", ... bremsstrahlung = "KKP95", # For physics model. ... seed = 123456, # For random engine. ... reference = "Gaisser90", ... )
Note that specifying a date enables the geomagnetic field, which is disabled by default. Alternatively, the geomagnetic field might also be enabled as,
>>> meter = mulder.Fluxmeter(geomagnet=True)
- flux(states=None, /, *, events=None, notify=None, **kwargs)#
Compute flux estimate(s).
This method uses the States interface for specifying the observation states(s) of interest. For instance, the following computes the flux at an altitude of 100 m and along an elevation angle of 30 deg.
>>> flux = meter.flux(altitude=100, elevation=30)
In mixed or detailed
mode, the events parameter specifies the number of reference states that are generated for each observation state in order to estimate the flux. In these cases, the method returns the flux and error estimates as anndarray. For instance,>>> flux, sigma = meter.flux(altitude=100, elevation=30, events=1000)
- transport(states=None, /, *, events=None, notify=None, **kwargs)#
Transport state(s) to the reference model.
This method uses the States interface for specifying the observation states(s) of interest. For instance, the following determines the reference state corresponding to an observation altitude of 100 m, along an elevation angle of 30 deg.
>>> state0 = meter.transport(altitude=100, elevation=30)
In mixed or detailed
mode, the events parameter specifies the number of reference states that are generated for each observation state. For example, the following returns anndarraycontaining a thousand reference states.>>> states0 = meter.transport(altitude=100, elevation=30, events=1000)
Attributes
- atmosphere#
The atmosphere model.
This attribute is an instance of a
mulder.Atmosphere, which controls the atmosphere properties. For convenience, the atmosphere model can be provided directly when setting this attribute. For example,>>> meter.atmosphere = "us-standard"
- geomagnet#
The geomagnetic field.
This attribute is an instance of a
mulder.EarthMagnet, which controls the geomagnetic field. For convenience, the geomagnetic model can be provided directly when setting this attribute. For example,>>> meter.geomagnet = "IGRF14.COF"
By default, the geomagnetic field is disabled.
- geometry#
The surrounding geometry.
This attribute is an
EarthGeometryor aLocalGeometry. For convenience, local geometry data can be provided directly when setting this attribute. For example,>>> meter.geometry = "geometry.toml"
- mode#
The transport mode.
Possible values are,
"continous","discrete"or"mixed". By default, the fluxmeter operates in continuous mode. For instance, the following switches the fluxmeter to discrete mode.>>> meter.mode = "discrete"
- physics#
The muon physics.
This attribute is an instance of a
mulder.Physics, which controls the physics of the muon transport.
- random#
The pseudo-random stream.
This attribute is an instance of a
mulder.Random, which controls the pseudo-randomness of simulated events.
- reference#
The reference muon flux.
This attribute is an instance of a
mulder.Reference, which controls the reference model for flux computations.
- class mulder.Random#
A Pseudo-Random Numbers Generator (PRNG).
This class manages a cyclic sequence of pseudo-random numbers over the interval \((0, 1)\). These numbers are exposed as a stream of
floats. The sequence is fully determined by theseedattribute, while theindexattribute indicates the stream state.Note
A Permuted Congruential Generator (PCG) is used (namely Mcg128Xsl64), which has excellent performances for Monte Carlo applications.
- __new__(seed=None, *, index=None)#
Creates a new pseudo-random stream.
If seed is
None, then a random value is picked using the system entropy. Otherwise, the specifiedseedvalue is used. For instance,>>> prng = mulder.Random(123456789)
- uniform01(shape=None, /)#
Generate pseudo-random number(s) uniformly distributed over (0,1).
If shape is
None, then a single number is returned. Otherwise, anumpy.ndarrayis returned, with the given shape. For instance, the following returns the next 100 pseudo-random numbers from the stream.>>> rns = prng.uniform01(100)
Attributes
- index#
The PRNG stream index.
This property can be modified, resulting in consuming or rewinding the pseudo-random stream. For instance, the following resets the stream.
>>> prng.index = 0
- seed#
The PRNG initial seed.
The property fully determines (and identifies) the pseudo-random sequence. Note that modifying the seed also resets the stream to index
0.
- class mulder.Reference#
This class represents a reference model of the muon flux. Typically, this is the opensky flux, i.e the atmospheric muon flux in the absence of any topographic features.
Mulder expresses the reference flux, \(\phi(K, \epsilon, z)\), as function of the muon kinetic energy, \(K\), and using geographic coordinates, where \(\epsilon\) is the elevation angle of observation and \(z\) the altitude. In addition, the contributions of muons (\(\phi_-\)) and anti-muons (\(\phi_+\)) are split, as \(\phi = \phi_+ + \phi_-\).
Alternatively, the reference flux might be set as flat, typically \(\phi = 1\) over a domain in \((K, \epsilon, z)\). This is especially relevant in conjuction with the
Fluxmeter.transport()method, e.g. to generate a sample of reference muons.- __new__(model=None, /, **kwargs)#
Creates a reference model.
The model argument might be,
an
arraycontaining a tabulation of the reference flux,a
Pathto a file containing a tabulated flux model,a
floatindicating a flat reference.
By default, i.e. if model is
None, the parametric model of [GCC+15] is used. For instance, as>>> reference = mulder.Reference()
- flux(states=None, /, **kwargs)#
Computes the reference flux.
This method uses the States interface for specifying the observation state of interest. For instance, using geographic coordinates,
>>> flux = reference.flux(elevation=30)
Attributes
Note
Referenceobjects are immutable, i.e. the underlying model or its support cannot be modified.- altitude#
Altitude (range) of the reference flux.
Depending on the reference model, the altitude might be a
floatconstant or an interval. For instance,>>> reference.altitude 0.0
- elevation#
Elevation range of the reference flux.
- energy#
Energy range of the reference flux.
Picture interface#
Mulder ray-tracing algorithms may be used to visualise a geometry (e.g., as a
cross-check). For this purpose, Mulder provides a
Camera object from which a
Projection of the geometry may be done (onto the
camera screen). The geometry is then rendered by applying a lighting model to
the projected data.
Important
Mulder ray-tracing algorithms are designed for particle transport. These algorithms are suboptimal for graphic applications.
Light sources
Mulder provides three types of light sources:
AmbientLight,
DirectionalLight, or
SunLight. It is also possible to define a
superposition of several light sources as a sequence, for example as
>>> lights = (
... picture.AmbientLight(intensity=0.1),
... picture.DirectionalLight(colour="gold"),
... )
The light intensity defines the source power on a linear scale, with a default intensity of 1. The light colour indicates the source spectral content. By default, light sources are white.
Colours
Mulder uses the sRGB colour space to specify colours, as a triplet of values within \([0, 1]\). For instance, the following defines purple as a balanced mixture of red and blue.
>>> purple = (1, 0, 1)
Alternatively, string-encoded matplotlib colours
may be employed. For instance,
>>> colour1 = "skyblue"
>>> colour2 = "#87CEEB"
- class mulder.picture.AmbientLight#
An ambient light source.
Ambient light sources provide uniform illumination, which, although convenient, may be counterintuitive in certain situations, for example when rendering outdoor scenes. In the latter case, a
SunLightwould be a more natural choice.- __new__(*, colour=None, intensity=None)#
Creates an ambient light source.
For instance, the following creates a dim golden ambient light source,
>>> light = picture.AmbientLight(colour="gold", intensity=0.1)
See the Light sources and Colours sections for further details.
Attributes
- colour#
The light colour.
- intensity#
The light intensity.
- class mulder.picture.Atmosphere#
Graphic properties of the atmosphere.
The atmosphere rendering is done following the Physically Based Rendering (PBR) model of [Hil20], adapted to Mulder. The atmosphere properties are set according to the Earth, and are immutable. For more information, please refer to [Hil20].
Note
This class is singleton. Please note that all methods below are class methods.
- aerial_view(projection, /, *, lights)#
Computes the aerial light.
The aerial light is computed over the input projection, which must be an instance of
Projection. Please refer to the Light sources section for information on the lights argument.
- ambient_light(position=None, /, *, lights, **kwargs)#
Computes the ambient light table.
This method uses the Position interface for specifying the camera position. For instance, using geographic coordinates
>>> ambient_light = picture.Atmosphere.ambient_light( ... lights = picture.SunLight(datetime="2025-06-21 15:00:00"), ... longitude = 3, ... latitude = 45, ... )
Please refer to the Light sources section for information on the lights argument.
- multiple_scattering()#
Returns the multiple scattering table.
- sky_view(position=None, /, *, lights, **kwargs)#
Computes the sky view table.
This method uses the Position interface for specifying the camera position. Please refer to the Light sources section for information on the lights argument.
- transmittance(elevation, /, *, altitude=None)#
Computes the transmittance value(s).
The elevation argument may be a scalar or an array. The corresponding transmittance is returned. The optional altitude argument specifies the origin of the ray(s).
- class mulder.picture.Camera#
A camera model.
This class represents a digital camera.
Cameraobjects are spawned using thecamera()method of aLocalFrame, which defines the camera’s position and orientation. For instance, as>>> camera = mulder \ ... .LocalFrame(elevation=15, altitude=1) \ ... .camera()
The camera manages a 2D grid of lines of sight, accessible via the
pixelsattribute. Geometries can be projected onto the camera screen using theproject()method.- project(geometry, /, *, ignore=None, notify=None)#
Projects a geometry.
This method encodes a geometry of interest as a raw
Projection, using photographic projection. For instance,>>> projection = camera.project(geometry)
Specific media can be made transparent by providing their indices as the optional ignore argument.
Attributes
Note
Camerainstances are immutable.- frame#
The camera reference frame.
The reference frame defines the camera position and orientation (i.e., the pointing direction). For instance, the following camera points towards the geographic north,
>>> camera.frame.azimuth 0.0
- focal#
The camera focal length.
The focal length is normalised to the screen width, and thus unit-less. The focal length determines the field of view (
FOV) of the camera.
- fov#
The camera horizontal field of view (FOV), in degrees.
The field of view (FOV) is in a bijective mapping with the camera
focallength.
- pixels#
The camera pixels.
The pixels matrix is exposed as a
Pixelsobject. For instance, the ray coordinates along teh camera pixels can be obtained as,>>> rays = camera.pixels.coordinates
- ratio#
The camera screen ratio (width / height).
Unless otherwise specified, the screen ratio is determined by the camera
resolutionassuming square pixels. Standard screen ratio values are 4:3 or 16:9.
- resolution#
The camera screen resolution (height, width), in pixels.
- class mulder.picture.DirectionalLight#
A directional light source.
Directional lights model a distant source, providing a locally flat illumination oriented along the source direction.
- __new__(azimuth=None, elevation=None, *, colour=None, intensity=None)#
Creates a directional light source.
For instance, the following creates a remote light source located along the south, at an elevation angle of 15 deg.
>>> light = picture.DirectionalLight(azimuth=180, elevation=15)
See the Light sources and Colours sections for further details.
Attributes
- azimuth#
The source azimuth direction, in deg.
- colour#
The light colour.
- elevation#
The source elevation direction, in deg.
- intensity#
The light intensity.
- class mulder.picture.Material#
Graphic properties of a material.
This class stipulates the graphic properties of a material. For more detailed information, please refer to the Filament documentation.
- __new__(*, colour=None, metallic=None, reflectance=None, roughness=None)#
Creates a new set of graphic properties.
See the attributes below for the meaning of arguments.
Attributes
- colour#
Perceived colour (albedo), in sRGB space.
See the Colours section for instructions on defining a colour.
- metallic#
Dielectric (false) or conductor (true).
Smooth metalic surfaces behave as mirrors, whereas dielectric surfaces are diffusive.
Tip
A
floatvalue in \([0, 1]\) may also be provided, for example, to represent a blend of dielectric and conductor materials.
- reflectance#
Specular intensity for non-metals, in [0, 1].
Fresnel reflectance at normal incidence for dielectric materials. This property is ignored for metals.
- roughness#
Surface roughness, in [0, 1].
Perceived smoothness (0.0) or roughness (1.0) of the material surface. Smooth surfaces exhibit sharp reflections.
- class mulder.picture.MaterialMap#
A Material map.
This class represents a linear blending of
Materialsparametrised by a scalar observable, \(\alpha\) (typically,altitudevalues). The mapping is defined by providing nodes, \((\alpha_i, M_i)\), between which the material properties (\(M\)) are linearly interpolated as a function of \(\alpha\).- __new__(nodes, /)#
Creates an new material map.
For example, the following defines a mapping from a green to brown
Materialfor parameter values (\(\alpha\)) ranging from 0 to 1000.>>> mmap = picture.MaterialMap(( ... ( 0, picture.Material(colour="darkgreen")), ... (1000, picture.Material(colour="saddlebrown")), ... ))
- material(alpha, /)#
Maps to a material.
This method returns the material properties corresponding to the input parameter value (\(\alpha\)). For instance,
>>> material = mmap.material(500)
Attributes
Note
MaterialMapinstances are immutable.- nodes#
The map nodes.
- mulder.picture.MATERIALS: dict#
A collection of materials graphic properties.
This
dictvariable maps the material names to their corresponding graphic properties (i.e., aMaterialorMaterialMap). For instance, the following modifies the colour of the Rock material.>>> picture.MATERIALS["Rock"].colour = "saddlebrown"
Additional materials might be defined as well, for example as follows
>>> picture.MATERIALS["Ice"] = picture.Material( ... metallic = True, ... roughness = 0.1, ... )
- class mulder.picture.Pixels#
A set of camera pixels.
Instances of this class are obtained by using the
pixelsattribute of aCameraobject. The camera pixels define a mapping between screen coordinates \((u, v)\) and lines of sight.Attributes
- azimuth#
The pixels azimuth direction, in degrees.
- coordinates#
The pixels geographic coordinates.
Tip
The pixels coordinates can be used as input to Mulder functions using the Coordinates interface, to iterate over the lines of sight defined by the camera pixels.
- elevation#
The pixels elevation direction, in degrees.
- u#
The pixels u coordinates.
This attribute represents the screen horizontal coordinates within the range of \([0, 1]\).
- v#
The pixels v coordinates.
This attribute represents the screen vertical coordinates within the range of \([0, 1]\).
- class mulder.picture.Projection#
A geometry projection.
Projection objects are generated with the
project()method of aCameraobject, e.g. as>>> projection = camera.project(geometry)
A projection object is used to encode the first
mediaobserved along the lines of sight of the camera, as well as the corresponding surfacenormalsat intersection points. This information can berenderedas a digital image by applying a lighting model.- normal(frame=None)#
Returns the surface normal at intersections.
The normal vectors are returned as a numpy
ndarrayof shape(height, width, 3). The coordinates are given in theLocalFramespecified as frame argument. If the latter argument is omitted, then the camera frame is assumed.
- render(*, atmosphere=None, data=None, exposure=None, lights=None, notify=None)#
Renders the projection as an image.
The image rendering is done following the Physically Based Rendering (PBR) model of Filament, adapted to Mulder.
Please refer to the Light sources section for information on the lights argument. Furthermore, for straightforward use cases the lighting model can also be specified as a
str. For instance, as>>> image = projection.render(lights="sun")
The supported models are
"ambient","directional"and"sun".If the atmosphere argument is set to
True, then the sky is rendered following [Hil20].Note
The atmosphere argument may also explicitly specify the index of the atmosphere medium.
The image exposure may be modified using the exposure argument, employing stops units (i.e. a base 2 logarithmic scale), with the value
0corresponding to the default exposure. For instance, the following reduces the image exposure by a factor of 2,>>> image = projection.render(exposure=-1)
The data argument specifies a mapping to be used in conjunction with a
MaterialMap, as adictobject mapping material names to parameter values. For instance, the following defines a mapping between the rock material and the projectedaltitudevalues.>>> image = projection.render(data={"Rock": projection.altitude})
Note that the provided parameter values must be consistent with the image shape.
- view(frame=None)#
Returns the view directions.
The view vectors indicate the direction of the camera lines of sight. The directions are returned as a numpy
ndarrayof shape(height, width, 3). The coordinates are expressed in theLocalFramewhich is provided as frame argument. When the latter argument is omitted, then the camera frame is used.
Attributes
- altitude#
The altitude at intersections, in meters.
This attribute is a mutable
ndarrayof shape(height, width).
- distance#
The distance to intersections, in meters.
This attribute is a mutable
ndarrayof shape(height, width).
- frame#
The camera reference frame.
- medium#
The visible media indices.
This attribute is a mutable
ndarray, of shape(height, width), containing the visible media indices. See the Geometry model section for further information.
- materials#
The materials mapping.
This attribute defines the mapping between media and materials, as a sequence of material names. For instance,
>>> projection.materials ('G4_AIR', 'G4_CALCIUM_CARBONATE')
This indicates that the first medium (of index
0) is composed of Geant4 air and the second (of index1) is composed of limestone (\(\mathrm{Ca}\mathrm{CO}_3\)). This mapping could be redefined, for instance using Mulder native materials, as>>> projection.materials = ('Air', 'Rock')
- class mulder.picture.SunLight#
A sun like light source.
This class models the Sun lighting, which is a particular case of
DirectionalLightwhose orientation is specified by a local date and solar time.- __new__(*, colour=None, datetime=None, intensity=None)#
Creates a sun light source.
The datetime argument determines the Sun location. This argument can be provided as a
datetimeobject, or as an ISO 8601 string. For instance, as>>> light = picture.SunLight(datetime="2025-06-21 13:00:00")
See the Light sources and Colours sections for further details.
Attributes
- colour#
The sun light colour.
- datetime#
The local date and solar time.
- intensity#
The sun light intensity.
Configuration data#
Configuration data can be accessed via the mulder.config singleton
class. For instance, as
>>> mulder.config.VERSION
'0.3.7'
The available configuration data are listed below.
- mulder.config.CACHE: Path#
The cache location.
Mulder uses a caching system to reduce the time taken for some time-consuming, yet repetitive tasks, such as the compilation of
Physicstables. This data indicates the location of cached files. For instance, the following changes the cache location>>> mulder.config.CACHE = "/tmp/mulder"
Note
By default, cache files are stored under
$HOME/.cache/mulder. This can be overriden by setting theMULDER_CACHEenvironment variable to the desired location.
- mulder.config.NOTIFY: bool#
Default status for notifications.
For operations that are potentially time-consuming, Mulder reports its progress to the terminal using a progress bar. By setting this flag to
False, such reports will be disabled, unless individual function calls explicitly set their notify argument toTrue.