Source code for irfpy.jdc.fluxsimulator

''' 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')