00001
00002
00003 #include "HeSpectrum.h"
00004
00005 #include "HeSpectrum.inc"
00006
00007 #include <cmath>
00008 #include <algorithm>
00009 #include <functional>
00010 #include "CLHEP/Random/Random.h"
00011 #include "GPS.h"
00012
00013 #include "SpectrumFactory.h"
00014
00015 static SpectrumFactory<HeSpectrum> factory;
00016 const ISpectrumFactory& HeSpectrumFactory = factory;
00017
00018
00019
00020
00021
00022
00023
00024
00025 HeSpectrum::InterpVec::InterpVec() : std::vector<float>() {}
00026
00027
00028
00029
00030 HeSpectrum::Intrp HeSpectrum::InterpVec::search(float x) const {
00031 using namespace std;
00032
00033
00034
00035
00036
00037 vector<float>::const_iterator loc;
00038 if (back() > front()) loc=lower_bound(begin(), end(), x, less<float>());
00039 else loc=lower_bound(begin(), end(), x, greater<float>());
00040
00041
00042 int ind;
00043 if (loc == begin()) ind = 1;
00044 else if (loc == end()) ind = (end() - begin()) - 1;
00045 else ind = (loc - begin());
00046
00047 return Intrp(ind, (x-(*this)[ind-1]) / ((*this)[ind]-(*this)[ind-1]));
00048 }
00049
00050
00051
00052 float HeSpectrum::InterpVec::interpolate(Intrp y) const {
00053
00054 return (*this)[y.first-1] +
00055 y.second * ((*this)[y.first]-(*this)[y.first-1]);
00056 }
00057
00058
00059
00060 const float HeSpectrum::m_rearth = 6371.f;
00061 const float HeSpectrum::m_altitude = 600.f;
00062
00063
00064 void HeSpectrum::init(float lat, float lon) {
00065
00066 int nen = sizeof(energies)/sizeof(float);
00067 m_en.reserve(nen);
00068 float amus = 4.;
00069 int i;
00070 for (i=0; i< nen; i++) m_en.push_back(amus*energies[i]/1000.);
00071
00072
00073 m_normfact = .5*(1.+sqrt(m_altitude*(m_altitude+2.*m_rearth)) /
00074 (m_rearth+m_altitude));
00075
00076 m_fluxes.reserve(nen);
00077 m_fl.reserve(nen);
00078
00079 const float width = 0.115f;
00080 m_etop = m_en.back() * (1.+.5*width);
00081 m_expo = -2.65f + 1.0f;
00082
00083
00084 float tfl = 0.f;
00085 for (i=74; i >= 0; i--) {
00086 tfl += width*1000.*m_en[i]*m_normfact*fluxes[i];
00087 m_fluxes.insert(m_fluxes.begin(), tfl);
00088 }
00089
00090
00091 for (int ii=0; ii < 73; ii++) {
00092 for (int jj=0; jj < 13; jj++) {
00093 m_fluxTbl[ii][jj] = gfluxes[jj+13*ii];
00094 }
00095 }
00096 setPosition(lat, lon);
00097
00098
00099 m_coscutoff = -sqrt(m_altitude*m_altitude+2.*m_altitude*m_rearth)
00100 / (m_altitude+m_rearth);
00101
00102 m_particle_name = "alpha";
00103
00104
00105 m_observer.setAdapter( new ActionAdapter<HeSpectrum>(this,
00106 &HeSpectrum::askGPS) );
00107
00108 GPS::instance()->notification().attach( &m_observer );
00109
00110 }
00111
00112
00113
00114
00115 HeSpectrum::HeSpectrum(const std::string& paramstring) {
00116 std::vector<float> params;
00117
00118 parseParamList(paramstring,params);
00119
00120 if(params.empty())
00121 init(0.0f,0.0f);
00122 else
00123 init(params[0], params[1]);
00124 }
00125
00126 std::string HeSpectrum::title() const {
00127 return "HeSpectrum";
00128 }
00129
00130 const char * HeSpectrum::particleName() const {
00131 return m_particle_name.c_str();
00132 }
00133 void HeSpectrum::setParticleName(std::string name)
00134 {
00135 m_particle_name = name;
00136 }
00137
00138
00139
00140 float HeSpectrum::flux(float cut) const {
00141
00142
00143
00144 if (cut > m_etop) return m_upper * pow(cut/m_etop, m_expo);
00145 else return m_upper + m_fl.interpolate(m_en.search(cut));
00146 }
00147
00148
00149
00150 double HeSpectrum::flux(double) const {
00151
00152 return m_flux;
00153 }
00154
00155
00156
00157 double HeSpectrum::solidAngle() const
00158 {
00159
00160 return 4.*M_PI;
00161 }
00162
00163
00164
00165 double HeSpectrum::flux(double lat, double lon) const {
00166
00167
00168 int ilat = static_cast<int>(lat/5.+6.);
00169 double a = fmod(lat+30., 5.)/5.;
00170 int ilon = static_cast<int>(lon/5.);
00171 double b = fmod(lon, 5.)/5.;
00172 return m_fluxTbl[ilon][ilat] * (1.-a) * (1.-b) +
00173 m_fluxTbl[ilon+1][ilat] * (1.-a) * b +
00174 m_fluxTbl[ilon][ilat+1] * a * (1.-b) +
00175 m_fluxTbl[ilon+1][ilat+1] * a * b;
00176 }
00177
00178
00179
00180 float HeSpectrum::operator() (float x)const {
00181
00182
00183 float join = (m_tot-m_upper)/m_tot;
00184 if (x < join) return m_en.interpolate(m_fl.search((1.-x)*m_tot-m_upper));
00185 else return m_etop*pow((1.-x)/(1.-join), 1./m_expo);
00186 }
00187
00188
00189
00190 int HeSpectrum::askGPS()
00191 {
00192 setPosition(GPS::instance()->lat(), GPS::instance()->lon());
00193 return 0;
00194 }
00195
00196 void HeSpectrum::setPosition(double lat, double lon) {
00197
00198
00199
00200
00201 m_lat = lat;
00202 m_lon = lon;
00203
00204
00205 m_upper = -0.115*1000.*m_en.back()*m_normfact*fluxes[74]
00206 * pow(1.+.5*0.115,m_expo)/(0.115*m_expo);
00207
00208 m_cutoff = findCutoff(lat,lon);
00209
00210
00211 float tfl = 0.;
00212 m_fl.erase(m_fl.begin(), m_fl.end());
00213 for (int i = 74; i >= 0; i--) {
00214 tfl += 0.115*1000.*m_en[i]*m_normfact*fluxes[i]*exposure(m_en[i]);
00215 m_fl.insert(m_fl.begin(), tfl);
00216 }
00217
00218 m_tot = m_fl.front() + m_upper;
00219 m_flux = flux(m_cutoff);
00220 }
00221
00222
00223
00224 float HeSpectrum::findCutoff(float rflux) const {
00225
00226 return m_en.interpolate(m_fluxes.search(rflux-m_upper));
00227 }
00228
00229
00230
00231 float HeSpectrum::findCutoff(float lat, float lon) const {
00232
00233 return findCutoff(flux(lat,lon));
00234 }
00235
00236
00237
00238
00239 double HeSpectrum::calculate_rate(double old_rate)
00240 {
00241 return flux(GPS::instance()->lat(), GPS::instance()->lon());
00242 }
00243
00244
00245
00246 float HeSpectrum::rad2() const {
00247
00248
00249
00250 double d2 =
00251 pow((m_rearth+m_altitude)*sin(m_lat) - 145.1, 2) +
00252 pow((m_rearth+m_altitude)*cos(m_lat)*cos(m_lon) + 371.2, 2) +
00253 pow((m_rearth+m_altitude)*cos(m_lat)*sin(m_lon) - 233.7, 2);
00254 return d2 / (m_rearth*m_rearth);
00255 }
00256
00257
00258
00259 float HeSpectrum::cosomega(float E) const {
00260
00261
00262
00263
00264
00265
00266
00267
00268 const float Mp = 4*0.938f;
00269 const float charge = 2.;
00270 float pcut = sqrt(m_cutoff*m_cutoff + 2.*Mp*m_cutoff);
00271 const float moment = 59.8f;
00272 float coslambda4 = 4. * pcut * rad2() / (charge*moment);
00273
00274 float p = sqrt(E*E + 2.*Mp*E);
00275 float coso = 4. * (sqrt(pcut/p) - pcut/p) * pow(coslambda4, -0.75);
00276
00277 if (coso > 1.) return 1.;
00278 else if (coso < -1.) return -1.;
00279 else return coso;
00280 }
00281
00282
00283
00284 float HeSpectrum::exposure(float E) const {
00285
00286 return 0.5 * (1. + cosomega(E));
00287 }
00288
00289
00290
00291 std::pair<float,float> HeSpectrum::dir(float energy)const
00292 {
00293
00294
00295
00296
00297
00298 float coszenith, sinpolar, cospolar, azi;
00299 const int try_max = 1000;
00300 static int max_tried = 0;
00301 int trial=0;
00302 do {
00303
00304 cospolar = -1. + HepRandom::getTheGenerator()->flat()*
00305 (cosomega(energy)+1.);
00306 sinpolar = sqrt(1.-cospolar*cospolar);
00307 azi = 2.*M_PI* HepRandom::getTheGenerator()->flat();
00308 coszenith = cos(azi)*sinpolar;
00309 } while (coszenith < m_coscutoff && trial++ < try_max);
00310
00311 max_tried = std::max(trial, max_tried);
00312
00313
00314 double earthazi = atan2(sinpolar*sin(azi), cospolar);
00315
00316 return std::make_pair<float,float>(coszenith, earthazi);
00317 }