Package: mcmodel
MCmodelA 3D Monte Carlo scattering code to keep track of individual parcels in a plane-parallel homogenous slabThe theory behind the model, many of its parameters, and model validation have been
described by Petrich et al. (2012),https://doi.org/10.1016/j.coldregions.2011.12.004The Monte Carlo code itself is implemented in C for speed and integrated
with a Python interface for convenience.License: Apache 2.0.InstallationRequirementsPython 2.7, 3.5, 3.6, 3.7. Should work on Linux, MacOS,
and Windows.NumpyWhen compiling from source, a C-compiler, and typically
setuptools and wheel.From PyPIRunpip install mcmodel. Done.
Later, upgrade withpip install -U mcmodel, or uninstall withpip uninstall mcmodel.Use without installationGet the latest source code fromhttps://github.com/cpetrich/MCmodelRunpython setup.py buildand copy the contents of thebuilt/lib.[...]directory into the same directory as your own modeling code.Installation with pipGet the latest source code fromhttps://github.com/cpetrich/MCmodelA wheel will be built locally and installed with pip.
Build the module and create a wheel file
withpython setup.py bdist_wheel,cd dist,pip install mcmodel-[...].whl. To uninstall the package later runpip uninstall mcmodel.TestTo test the result of the build process, a rather incomplete test suite
can be run withpython setup.py test.LimitationsThe code is currently not reentrant since it uses global state for the random
number generator, the phase function, and buffers that hold detailed information
about the most recent particle track. I.e., only one instance of the model per
process.The special case - in a scattering model - of "no scattering" (w0 == 0) is
implemented only fork == 0(i.e. no absorption).UsageThe usual mode of operation is:seed the random number generatordefine a scattering phase functioncall the scattering code with slab optical properties, and position and direction of one parcel of lightstore entrance and exit positions and angles of the parcel and information about plane crossings inside the mediumif desired, store complete track of the light parcelcontinue with (2) a couple of thousand or million times.read the simulation results from disk, and determine parcel intensity due to absorption and Fresnel reflectionanalyze result as desiredAn example of seeding the random number generator of the Monte Carlo model isimport os
import mcmodel
mcmmodel.set_seed(int.from_bytes(os.urandom(4),'little'))A helper function exists to generate common scattering phase functions, e.g.import mcmodel_util
pf = mcmodel_util.make_phase_function('Henyey-Greenstein', (0.98, 0))The phase function is transfered to the model code likemcmodel.define_phase_function(pf['lookup_cdf'],pf['lookup_phi'])A random number generator is usually used to generate an incoming distribution
(that random number generator is separate from the one used by the Monte Carlo
model and should also be seeded).import random
random.seed()A sample from the angular distribution of a Lambert emitter
(i.e., overcast over snow-covered ground) isimport math

elevation_angle = math.arcsin(random.uniform(-1., 0))
azimuth = random.uniform(-math.pi, math.pi)Note that the Monte Carlo code works inelevationangles. A normally
incident beam at the upper surface of the slab has an elevation angle
of -pi/2.The domain parameters and incident angle are passed on to the Monte Carlo
code in a dictionary, e.g.in = {'angle': elevation_angle,
      'azimuth': azimuth,
      'thickness': 1, # slab thickness
      'k': 1}         # densiy of microscopic interactions used by the modelwith additional optional input parameters described below. Many of the output
data are obtained through updates to a dictionary that is passed to the scattering
simulation. To calculate the track of a single parcel callout = {}
mcmodel.simulate(in, out)where exit position and angles areexit_position = (out['x'], out['y'], out['z'])
exit_elevation_angle = out['angle']
exit_azimuth = out['azimuth']
path_length = out['path_length']Attenuation of the parcel inside the medium is accounted for by decreasing its
amplitude. The precise method of this depends on the definition and units of
thickness and microscopic extinction coefficient passed into the model above.
However, the intensity of the emerging parcel will be of a form similar toexit_intensity = math.exp(-kappa * path_length)where kappa is the absorption coefficient.Intensity reduction due to Fresnel reflection (other than total reflection)
would be accounted for based on entrance and exit angles and relative refractive
indices. To do this in hindsight is not trivial and requires the simulations
to be run with a relative refractive index of 1 and appropriate scaling of
the input angular distribution to account for non-trivial refractive indices.
This is outside the scope of this overview.[TODO: in a future version, add an option to have Monte Carlo model take care
of this by selecting a path stochastically.]APIThe C code exports currently four functions (see Usage above):mcmodel.set_seed(...)mcmodel.define_phase_function(..., ...)mcmodel.simulate(..., ...)mcmodel.get_last_particle_track()In addion, there is one helper function defined in Pythonmcmodel_util.make_phase_function(...)ParametersThe model domain is a horizontal slab of thicknessthickness, extending fromz=0at the upper surface toz=-thicknessat the bottom. Parcles are injected
at depthz=z0(-thickness <= z0 <= 0) andx=0andy=0. Injection atz0 = -thicknessandz0 = 0are on the outside of the slab at the lower and
upper interface, respectively (i.e. still subject to refraction).If an anisotropic scattering coefficient is used, i.e.sigma_anisotropy != 0,
then the vertical and horizontal scattering coefficients aresigma_v = k * w0andsigma_h = k * w0 * (sigma_anisotropy+1), respectively.Input Dictionary ofmcmodel.simulate()NameDefaultMeaninganglenoneelevation angle of incident parcel [-pi; pi]azimuthnoneazimuth angle of incident parcel [-pi; pi)z00vertial coordinate of parcel injectionthicknessnoneslab thicknessknonemicroscopic extinction coefficientw01single scattering albedon_surface1refractive indexn_slab / n(z>0)n_bottom1refractive indexn_slab / n(z<-thickness)sigma_anisotropy0anisotropy of scattering coefficient (cf. Trodahl et al.),sigma_anisotropy = sigma_h/sigma_v - 1do_record_trackFalselog coordinates of scattering the parcel. Retrieve withmcmodel.get_last_particle_track()do_record_plane_crossingsFalselog position and angle of parcel every time it crosses specified planesrecord_planes[]list ofzcoordinates to record parcel crossings atOutput Dictionary ofmcmodel.simulate()NameMeaningangle_incopy ofanglein input dictionaryazimuth_incopy ofazimuthin input dictionaryangleexit eleation angle of parcelazimuthexit azimuth of parcelxlateral exit coordinate, same unit asthicknessin inputylateral exit coordinate, same unit asthicknessin inputzvertical exit coordinate, same unit asthicknessin inputpath_lengthtotal path length of parcel in the medium, same unit asthicknessin inputexit_direction+1: exit atz=0,-1: exit atz=-thicknessmin_zlowestzcoordinate along the trackmax_Rlargest value ofsqrt( x^2 + y^2 )along the trackn_collisionsnumber of scattering events along the path (NB: not total reflection)n_missed_collisionsnumber of absorption events along the path, all of which have been ignored (count is slightly too high ifw0>0)n_refractionsnumber of refractions experienced along the pathn_total_reflectionsnumber of total reflections along the pathn_plane_crossingsnumber of plane crossing events along the pathplane_crossings2Dnumpyarray containing 6 entries (columns) per crossing event (see below)The six column entries for each plane crossing are:elevation angleazimuth anglex-coordinate at the point of crossingy-coordinate at the point of crossingz-coordinate at the point of crossingparcel path length so far