''' Flux and count rate simulator.
For preparatory, flux simulator is very useful.
'''
import numpy as np
import irfpy.util.maxwell
import irfpy.pep.pep_attitude
from . import energy0 as energy
from . import fov0 as fov
from . import flux0 as flux
from . import frame0 as frame
[docs]class SimpleSimulator:
''' Simulator class. Only single species support.
A simple simulator of the flux.
No optimization, therefore, very slow, indeed.
Anyway, you can use as follows:
>>> sim = SimpleSimulator()
>>> sim.set_species(32., 2.)
The above statement set the mass=32 charge=2 for the target atom.
If you do not specify, oxygen singly charged ion (m=16, q=1) is used by default.
Then you should specify the distribution function, otherwise nan is returned.
Here, a simplest method is using :meth:`set_plasmaparameter`.
This will create Maxwell distribution from the given parameter.
>>> sim.set_plasmaparameter(1e6, 0, 0, 5e3, 10e3)
More flexible way is to prepare an arbitorary function, that get (3,) shape
array (velocity) returning the scalar (velocity distribution function),
and use :meth:`set_velocitydistribution`.
Either the above, after setting the velocity distribution function,
you can choose the energy, elevation and azimuthal index.
(Index is defined in :mod:`irfpy.jdc.fov0` and :mod:`irfpy.jdc.energy0`.)
>>> print('%.2f' % sim.get_dflux(18, 5, 12))
1148.71
>>> print('%.4f' % sim.get_countrate(18, 5, 12))
2.8985
It returns the differential flux in #/cm2 sr eV s and count rate in #/s
for the energy step 18, elevation index 5 and azimuthal index 12.
'''
def __init__(self):
''' Initializer
'''
m = 16.
q = 1.
self.sc = irfpy.pep.pep_attitude.NadirLookingSc()
self.sc.set_posvel([-3000e3, 0, 0], [0, 1e3, 0])
self.enevlist = energy.getEnergy()
self.set_species(m, q)
self.ellist = np.arange(32)
self.azlist = np.arange(16)
self.f2c = flux.Flux2Count()
self.f = lambda p: np.nan
[docs] def set_species(self, m, q):
''' Set the mass and charge for the species.
'''
self.mass = m * 1.67e-27
self.charge = q * 1.60e-19
self.vellist = np.sqrt(self.enevlist) * np.sqrt(2. * self.charge / self.mass)
[docs] def set_velocitydistribution(self, f):
'''
'''
self.f = f
[docs] def set_plasmaparameter(self, n, vx, vy, vz, vth):
''' A special functin to set the single species Maxwellian.
:param n: Density in /m3
:param vx,vy,vz: Velocity in m/s
:param vth: Thermal velocity in m/s
'''
f = irfpy.util.maxwell.mkfunc(n, (vx, vy, vz), vth)
self.set_velocitydistribution(f)
[docs] def set_spacecraft_pvat(self, pos, vel):
''' Spacecraft position and velocity is used to calculate the nadir pointing spacecraft.
'''
self.sc.set_posvel(pos, vel)
[docs] def get_dflux(self, iene, iel, iaz):
''' Return the differential flux at the given bin.
'''
el = fov.elev_pix_center(iel)
az = fov.azim_pix_center(iaz)
## Looking direction.
lookingdir_jdc = frame.angles2jdc(el, az) # (3,)
## Looking direction in SC
lookingdir_nsc = frame.jdc2nsc(lookingdir_jdc)
# conversion to physical reference.
lookingdir_ref = self.sc.convert_to_ref(lookingdir_nsc)
# The looking dir and observing velocity vector is opposite.
velocitydir_ref = -lookingdir_ref
vel = self.vellist[iene]
vvec = velocitydir_ref * vel
fval = self.f(vvec) # Velocity distribution function
dflux = fval / self.mass * (vel ** 2)
dflux = dflux / 1e4 * self.charge # Convert to */cm2 sr eV s
return dflux
[docs] def get_countrate(self, iene, iel, iaz):
''' Return the count rate
'''
dflux = self.get_dflux(iene, iel, iaz)
return self.f2c.getCounts(dflux, iene)
import unittest
import doctest
[docs]def doctests():
return unittest.TestSuite((
doctest.DocTestSuite(),
))
if __name__ == '__main__':
unittest.main(defaultTest='doctests')