00001
00002
00003 #include "FluxSvc/FluxSource.h"
00004
00005 #include "dom/DOM_Element.hpp"
00006 #include "dom/DOM_NodeList.hpp"
00007 #include "xml/Dom.h"
00008
00009 #include "SpectrumFactoryTable.h"
00010
00011 #include "SimpleSpectrum.h"
00012
00013 #include "CLHEP/Random/RandFlat.h"
00014
00015 #include "geometry/CoordTransform.h"
00016 #include "geometry/Ray.h"
00017 #include "geometry/Box.h"
00018
00019 #include "Orbit.h"
00020 #include "astro/SkyDir.h"
00021
00022 #include "FluxException.h"
00023
00024 double FluxSource::s_backoff;
00025 double FluxSource::s_radius=1.0;
00026
00027
00028 #include <algorithm>
00029 #include <list>
00030 using std::min;
00031 using std::max;
00032
00033
00034 FluxSource::FluxSource(ISpectrum* aSpec, double aFlux)
00035 : EventSource(aFlux), m_spectrum(0),
00036 m_maxEnergy(100.),
00037 _minCos(-0.4f), _maxCos(1.0f), _minPhi(0.0f), _maxPhi(2*M_PI),
00038 m_rmin(0), m_rmax(1), _phi(0.0f), _theta(0.0f), m_pointtype(NOPOINT),
00039 m_launch(NONE), illumBox(0), m_energyscale(GeV) ,m_degreespread(0)
00040 {
00041 s_backoff = 0.;
00042 spectrum(aSpec);
00043 useSpectrumDirection();
00044 setAcceptance();
00045
00046 }
00047
00048
00049 FluxSource::FluxSource(double aFlux, ISpectrum* aSpec, double l, double b)
00050 : EventSource(aFlux), m_spectrum(0),
00051 m_maxEnergy(100.),
00052 _minCos(-0.4f), _maxCos(1.0f), _minPhi(0.0f), _maxPhi(2*M_PI),
00053 m_rmin(0), m_rmax(1), _phi(0.0f), _theta(0.0f), m_pointtype(NOPOINT),
00054 m_launch(NONE), illumBox(0),m_gall(l),m_galb(b),m_degreespread(0)
00055 {
00056 s_backoff = 0.;
00057 spectrum(aSpec);
00058
00059
00060
00061 getGalacticDir(l,b);
00062
00063 m_launch=GALACTIC;
00064 setAcceptance();
00065
00066 }
00067
00068
00069 FluxSource::FluxSource(const DOM_Element& xelem )
00070 : EventSource (xelem), m_spectrum(0),
00071 m_maxEnergy(100.),
00072 _minCos(-0.4f), _maxCos(1.0f), _minPhi(0.0f), _maxPhi(2*M_PI),
00073 m_rmin(0), m_rmax(1), _phi(0.0f), _theta(0.0f), m_pointtype(NOPOINT), m_launch(NONE),
00074 illumBox(0), m_energyscale(GeV),m_degreespread(0)
00075 {
00076 static double d2r = M_PI/180.;
00077
00078 ISpectrum* s = 0;
00079 std::string class_name;
00080 std::string source_params;
00081
00082 DOM_Element spec = xml::Dom::findFirstChildByName(xelem, "spectrum");
00083
00084 if (spec == DOM_Element()) {
00085
00086
00087
00088 class_name = xml::Dom::transToChar(xelem.getAttribute("name"));
00089 useSpectrumDirection();
00090
00091 } else {
00092
00093 DOM_NodeList children = spec.getChildNodes();
00094
00095
00096 DOM_Node childNode = children.item(0);
00097 DOM_Element specType;
00098
00099 if (childNode.getNodeType() == DOM_Node::ELEMENT_NODE) {
00100 specType = (DOM_Element &) childNode;
00101 }
00102 else specType = xml::Dom::getSiblingElement(childNode);
00103
00104 DOMString typeTagName = specType.getTagName();
00105 std::string spectrum_name = xml::Dom::transToChar(spec.getAttribute("name"));
00106
00107 std::string spectrum_energyscale = xml::Dom::transToChar(spec.getAttribute("escale"));
00108
00109
00110
00111
00112
00113
00114 if(spectrum_energyscale == "GeV"){ m_energyscale=GeV;
00115 }else if(spectrum_energyscale == "MeV"){ m_energyscale=MeV;
00116 }else{
00117 std::cout << "bad energy scale declaration on spectrum:"
00118 << spectrum_energyscale << " , exiting.";
00119 return;}
00120
00121
00122 if (typeTagName.equals("particle")) s = new SimpleSpectrum(specType);
00123 else if (typeTagName.equals("SpectrumClass")) {
00124
00125 class_name = xml::Dom::transToChar(specType.getAttribute("name"));
00126 source_params= xml::Dom::transToChar(specType.getAttribute("params"));
00127 }
00128 else {
00129
00130 class_name = xml::Dom::transToChar(typeTagName);
00131 }
00132
00133 DOM_Element angles = xml::Dom::getSiblingElement(specType);
00134 DOMString anglesTag = angles.getTagName();
00135
00136 if (anglesTag.equals("solid_angle") ) {
00137 setLaunch(atof(xml::Dom::transToChar(angles.getAttribute("theta"))) * d2r,
00138 atof(xml::Dom::transToChar(angles.getAttribute("phi"))) *d2r);
00139 setCosThetaRange(atof(xml::Dom::transToChar(angles.getAttribute("mincos"))),
00140 atof(xml::Dom::transToChar(angles.getAttribute("maxcos"))) );
00141 }
00142 else if (anglesTag.equals("direction") ) {
00143 setLaunch(atof(xml::Dom::transToChar(angles.getAttribute("theta"))) * d2r,
00144 atof(xml::Dom::transToChar(angles.getAttribute("phi"))) *d2r);
00145 }
00146 else if (anglesTag.equals("use_spectrum") ) {
00147 std::string frame = xml::Dom::transToChar(angles.getAttribute("frame"));
00148
00149 if(frame == "galaxy"){
00150 m_launch=SPECGAL;
00151 }else{
00152 useSpectrumDirection();
00153 }
00154 }
00155 else if(anglesTag.equals("galactic_dir")){
00156 m_galb=atof(xml::Dom::transToChar(angles.getAttribute("b")));
00157 m_gall=atof(xml::Dom::transToChar(angles.getAttribute("l")));
00158 getGalacticDir(atof(xml::Dom::transToChar(angles.getAttribute("l"))),
00159 atof(xml::Dom::transToChar(angles.getAttribute("b"))) );
00160 m_launch=GALACTIC;
00161 }
00162 else if(anglesTag.equals("celestial_dir")){
00163
00164 double ra=atof(xml::Dom::transToChar(angles.getAttribute("ra")));
00165 double dec=atof(xml::Dom::transToChar(angles.getAttribute("dec")));
00166 astro::SkyDir tempdir(ra,dec);
00167 m_galb=tempdir.b();
00168 m_gall=tempdir.l();
00169
00170
00171 getGalacticDir(m_gall,m_galb);
00172 m_launch=GALACTIC;
00173 }
00174 else if(anglesTag.equals("galactic_spread")){
00175
00176 m_galb=atof(xml::Dom::transToChar(angles.getAttribute("b")));
00177 m_gall=atof(xml::Dom::transToChar(angles.getAttribute("l")));
00178 m_degreespread = atof(xml::Dom::transToChar(angles.getAttribute("degreespread")));
00179
00180
00181 m_launch=SPREAD;
00182 }
00183 else {
00184 FATAL_MACRO("Unknown angle specification in Flux::Flux \""
00185 << xml::Dom::transToChar(anglesTag) << "\"" );
00186 }
00187
00188
00189 DOM_Element launch = xml::Dom::getSiblingElement(angles);
00190
00191 if(launch !=DOM_Element()) {
00192 DOMString launchTag = launch.getTagName();
00193
00194 if(launchTag.equals("launch_point")){
00195 m_pointtype=SINGLE;
00196 LaunchType templaunch=m_launch;
00197
00198 setLaunch(m_launchDir,
00199 Point(atof(xml::Dom::transToChar(launch.getAttribute("x"))),
00200 atof(xml::Dom::transToChar(launch.getAttribute("y"))),
00201 atof(xml::Dom::transToChar(launch.getAttribute("z"))) ) );
00202 m_launch=templaunch;
00203
00204 }else if(launchTag.equals("patch")){
00205
00206 m_pointtype = PATCH;
00207 LaunchType templaunch=m_launch;
00208
00209
00210
00211 setLaunch( (-launchDir()).theta(), (-launchDir()).phi(),
00212 atof(xml::Dom::transToChar(launch.getAttribute("xmax"))),
00213 atof(xml::Dom::transToChar(launch.getAttribute("xmin"))),
00214 atof(xml::Dom::transToChar(launch.getAttribute("ymax"))),
00215 atof(xml::Dom::transToChar(launch.getAttribute("ymin"))),
00216 atof(xml::Dom::transToChar(launch.getAttribute("zmax"))),
00217 atof(xml::Dom::transToChar(launch.getAttribute("zmin")))
00218 );
00219
00220 m_launch=templaunch;
00221
00222
00223 }else {
00224 FATAL_MACRO("Unknown launch specification in Flux::Flux \""
00225 << xml::Dom::transToChar(launchTag) << "\"" );
00226 }
00227 }
00228
00229 }
00230 if( s==0) {
00231
00232 s = SpectrumFactoryTable::instance()->instantiate(class_name, source_params);
00233 if(s==0){
00234
00235 std::cerr << "List of known Spectrum classes:\n" ;
00236 std::list<std::string>list= SpectrumFactoryTable::instance()->spectrumList();
00237 for( std::list<std::string>::iterator i = list.begin(); i!=list.end(); ++i)
00238 std::cerr << "\t" << *i << std::endl;
00239 FATAL_MACRO("Unknown Spectrum: "<< class_name);
00240 return;
00241 }
00242 }
00243
00244
00245 FluxSource::spectrum(s);
00246
00247 s_backoff = 0.;
00248 setAcceptance();
00249
00250
00251
00252 }
00253
00254
00255 FluxSource::~FluxSource()
00256 {
00257 delete m_spectrum;
00258 if(illumBox) delete illumBox;
00259 }
00260
00261 inline static double sqr(double x) {return x*x; }
00262
00263
00264 void FluxSource::setAcceptance()
00265 {
00266
00267 s_radius = sqrt(totalArea() / M_PI ) * 1000;
00268 if(!s_backoff) s_backoff = s_radius;
00269
00270 switch (m_launch) {
00271
00272 case NONE:
00273 EventSource::solidAngle( (_maxCos - _minCos)*(_maxPhi - _minPhi) );
00274 break;
00275 case DIRECTION:
00276 case POINT:
00277 case GALACTIC:
00278 case SPECTRUM:
00279
00280 EventSource::solidAngle( m_spectrum==0? 1.0 : m_spectrum->solidAngle());
00281 break;
00282 case SURFACE:
00283 EventSource::solidAngle( (_maxCos - _minCos) * (_maxPhi - _minPhi) );
00284 if (_maxCos == _minCos) EventSource::solidAngle(1.);
00285 break;
00286 case PATCHFIXED:
00287 EventSource::solidAngle(1.0);
00288 break;
00289 case SPREAD:
00290 EventSource::solidAngle(M_PI*pow(m_degreespread*M_PI/180.,2));
00291 if (m_degreespread == 0.0) EventSource::solidAngle(1.);
00292 break;
00293 }
00294 }
00295
00296 void FluxSource::spectrum(ISpectrum* s, double emax)
00297 {
00298 if (emax > 0) {
00299 setMaxEnergy(emax);
00300
00301 std::cerr << "exercising obsolete function fraction" << std::endl;
00302 }
00303
00304 m_spectrum = s;
00305
00306 }
00307
00308
00309 FluxSource* FluxSource::event(double time)
00310 {
00311
00312
00313
00314 m_extime = 0;
00315
00316
00317
00318
00319 do{
00320 calculateInterval(time+m_extime);
00321
00322 computeLaunch(time+m_extime+m_interval);
00323
00324
00325 m_extime+=m_interval;
00326 }while(occluded() || m_interval == -1);
00327 m_extime -= m_interval;
00328
00329
00330
00331 m_interval += m_extime;
00332 EventSource::setTime(time+m_interval+m_extime);
00333 correctForTiltAngle();
00334 return this;
00335
00336 }
00337
00338
00339
00340 void FluxSource::randomLaunchPoint()
00341 {
00342
00343 HepRotation r_pln;
00344
00345 double ly = m_launchDir.y(), lx = m_launchDir.x();
00346 if( lx !=0 || ly !=0 )r_pln.rotate(acos(m_launchDir.z()),
00347 Vector(-ly, lx, 0.));
00348
00349
00350
00351 double azimuth = RandFlat::shoot( 2*M_PI );
00352 double rad = s_radius*(sqrt(RandFlat::shoot()));
00353
00354
00355
00356
00357
00358
00359 Vector posLaunch(rad*cos(azimuth), rad*sin(azimuth), 0.);
00360
00361
00362 CoordTransform t(r_pln, Vector(0,0,0) );
00363 t.transformVector(posLaunch);
00364
00365
00366 m_launchPoint = (Point&)posLaunch - m_launchDir*s_backoff;
00367 }
00368
00369
00370
00371 double FluxSource::flux(double time) const
00372 {
00373
00374 if(!enabled()){ return 0;}
00375 if(m_spectrum->flux(time)){ return m_spectrum->flux(time);}
00376 else{return EventSource::flux(time);}
00377 }
00378
00379 #if 1
00380 double FluxSource::solidAngle() const
00381 {
00382
00383 return EventSource::solidAngle();
00384 }
00385 #endif
00386
00387 void FluxSource::computeLaunch (double time)
00388 {
00389
00390
00391
00392 const double fudge=1.001;
00393 double kinetic_energy;
00394
00395
00396
00397 kinetic_energy = spectrum()->energySrc( HepRandom::getTheEngine(), time );
00398
00399
00400
00401
00402
00403 switch (m_launch) {
00404 case SPECTRUM:
00405 {
00406
00407
00408 std::pair<float,float> direction = spectrum()->dir(kinetic_energy,HepRandom::getTheEngine());
00409 double costh = direction.first;
00410 double sinth = sqrt(1.-costh*costh);
00411 double phi = direction.second;
00412 Vector v(cos(phi)*sinth, sin(phi)*sinth, costh);
00413 m_launchDir = -v;
00414
00415
00416
00417
00418 if (_theta != 0.0) m_launchDir.rotateX(_theta).rotateZ(_phi);
00419
00420 if(m_pointtype==NOPOINT){
00421 randomLaunchPoint();
00422 }
00423 break;
00424 }
00425 case SPECGAL:
00426 {
00427
00428 std::pair<float,float> direction = spectrum()->dir(kinetic_energy,HepRandom::getTheEngine());
00429 double l = direction.first;
00430 double b = direction.second;
00431
00432 getGalacticDir(l,b);
00433 m_launch = SPECGAL;
00434 break;
00435 }
00436 case GALACTIC:
00437 {
00438
00439
00440 getGalacticDir(m_gall, m_galb);
00441 break;
00442 }
00443 case SPREAD:
00444 {
00445 getGalacticDir(m_gall, m_galb);
00446 m_launch = SPREAD;
00447 spreadTheDirection();
00448 correctForTiltAngle();
00449 break;
00450 }
00451 case SURFACE:
00452 {
00453 getSurfacePosDir();
00454 break;
00455 }
00456 case PATCHFIXED: {
00457
00458
00459 if (_theta == 0.0) {
00460
00461 double xInc = patchXmin + patchWidX * RandFlat::shoot();
00462 double yInc = patchYmin + patchWidY * RandFlat::shoot();
00463 double zInc = patchTop;
00464 m_launchPoint = Point(xInc, yInc, zInc);
00465 } else {
00466 double dist = FLT_MAX;
00467 const double distToSearch = 500.;
00468 do {
00469 randomLaunchPoint();
00470
00471 Ray trialRay(m_launchPoint, m_launchDir);
00472 dist = illumBox->distanceToEnter(trialRay, distToSearch);
00473
00474 if (dist < FLT_MAX) m_launchPoint = trialRay.position(dist);
00475
00476
00477 } while (dist >= FLT_MAX);
00478 }
00479 break;
00480 }
00481 case NONE:
00482 {
00483 double costh = -RandFlat::shoot(_minCos, _maxCos);
00484 double sinth = sqrt(1.-costh*costh);
00485 double phi = RandFlat::shoot(_minPhi, _maxPhi);
00486
00487
00488
00489 m_launchDir = Vector(cos(phi)*sinth, sin(phi)*sinth, costh);
00490
00491
00492 if (_theta != 0.0) m_launchDir.rotateX(_theta).rotateZ(_phi);
00493 }
00494
00495 case DIRECTION:
00496 {
00497
00498 }
00499
00500 case POINT:
00501
00502 break;
00503
00504 }
00505
00506
00507 if(m_energyscale==MeV){
00508 m_energy = kinetic_energy;
00509 }else if(m_energyscale==GeV){
00510 m_energy = kinetic_energy*1000.;
00511 }
00512
00513
00514 switch (m_pointtype) {
00515 case NOPOINT:
00516 {
00517 randomLaunchPoint();
00518 break;
00519 }
00520
00521 case SINGLE:
00522 {
00523 break;
00524 }
00525 case PATCH:
00526 {
00527
00528
00529 if (_theta == 0.0) {
00530
00531 double xInc = patchXmin + patchWidX * RandFlat::shoot();
00532 double yInc = patchYmin + patchWidY * RandFlat::shoot();
00533 double zInc = patchTop;
00534 m_launchPoint = Point(xInc, yInc, zInc);
00535 } else {
00536 double dist = FLT_MAX;
00537 const double distToSearch = 500.;
00538 do {
00539 randomLaunchPoint();
00540
00541 Ray trialRay(m_launchPoint, m_launchDir);
00542 dist = illumBox->distanceToEnter(trialRay, distToSearch);
00543
00544 if (dist < FLT_MAX) m_launchPoint = trialRay.position(dist);
00545
00546
00547 } while (dist >= FLT_MAX);
00548 }
00549 break;
00550 }
00551 }
00552
00553
00554 }
00555
00556 std::string FluxSource::fullTitle () const
00557 {
00558 return title();
00559 }
00560
00561 std::string FluxSource::displayTitle () const
00562 {
00563 std::strstream s;
00564 s << EventSource::displayTitle() << '(' << m_spectrum->title() ;
00565 s << ')' << '\0';
00566 std::string t(s.str());
00567 s.freeze(false);
00568 return t;
00569 }
00570
00571 int FluxSource::eventNumber()const
00572 {
00573 return 0;
00574 }
00575
00576 void FluxSource::setCosThetaRange(double minc, double maxc)
00577 {
00578
00579 _minCos = min(minc,maxc);
00580 _maxCos = max(minc,maxc);
00581 if(_minCos==_maxCos) {
00582 if(_minCos!=-1) _minCos-=0.001; else _maxCos +=0.001;
00583 }
00584 m_launch = NONE;
00585 setAcceptance();
00586 }
00587
00588 void FluxSource::setPhiRange(double min_phi, double max_phi)
00589 {
00590
00591 _minPhi = min_phi;
00592 _maxPhi = max_phi;
00593 m_launch = NONE;
00594 setAcceptance();
00595 }
00596 void FluxSource::setLaunch(const Vector& dir, const Point& pos)
00597 {
00598
00599 m_launchDir = dir;
00600 m_launchPoint = pos;
00601 m_launch = POINT;
00602 }
00603 void FluxSource::useSpectrumDirection()
00604 {
00605 m_launch = SPECTRUM;
00606 }
00607
00608
00609 void FluxSource::setLaunch(double theta, double phi)
00610 {
00611
00612 _theta = theta;
00613 _phi = phi;
00614 Vector dir(sin(_theta)*cos(_phi),sin(_theta)*sin(_phi),cos(_theta));
00615 setLaunch(-dir);
00616 }
00617
00618 void FluxSource::setLaunch(const Vector& dir)
00619 {
00620
00621 m_launchDir = dir.unit();
00622 m_launch = DIRECTION;
00623 _theta = (-dir).theta();
00624 _phi = (-dir).phi();
00625 setAcceptance();
00626 }
00627
00628 void FluxSource::setLaunch(double theta, double phi, double xMax,
00629 double xMin, double yMax, double yMin,
00630 double zTop, double zBot) {
00631
00632
00633
00634
00635 double epsilon = 1e-5;
00636
00637 if (zTop < zBot) {
00638 WARNING_MACRO("zTop < zBot -- SWAPPING");
00639 std::swap(zTop, zBot);
00640 }
00641
00642 patchTop = zTop;
00643 patchBottom = zBot;
00644 patchHeight = fabs(zTop - zBot);
00645 if(patchHeight < epsilon) patchHeight = 0.0;
00646
00647 if (xMax < xMin) {
00648 WARNING_MACRO("patchXmax < patchXmin in Flux -- SWAPPING");
00649 std::swap(xMax, xMin);
00650 }
00651
00652 if( yMax < yMin) {
00653 WARNING_MACRO("patchYmax < patchYmin in Flux -- SWAPPING");
00654 std::swap(yMax, yMin);
00655 }
00656
00657 patchXmax = xMax;
00658 patchXmin = xMin;
00659 patchYmax = yMax;
00660 patchYmin = yMin;
00661
00662 patchWidX = fabs(patchXmax - patchXmin);
00663 patchWidY = fabs(patchYmax - patchYmin);
00664 if(patchWidX < epsilon) patchWidX = 0.0;
00665 if(patchWidY < epsilon) patchWidY = 0.0;
00666
00667 if( (patchHeight == 0.0) && ( (patchWidX == 0.0) || (patchWidY == 0.0) ) ) {
00668 FATAL_MACRO("zero area illumination\n");
00669 }
00670 if( (patchWidX == 0.0) && (patchWidY == 0) ) {
00671 FATAL_MACRO("zero area illumination!\n");
00672 }
00673
00674
00675 if ((theta == 0.0) && (patchHeight != 0.0)) {
00676 WARNING_MACRO("on-axis, but zTop != zBot, setting zBot = zTop\n");
00677 patchHeight = 0.0;
00678 patchBottom = patchTop;
00679 }
00680
00681
00682
00683 if (patchHeight <= 0.0) patchHeight = 0.0001;
00684 if (patchWidX <= 0.0) patchWidX = 0.0001;
00685 if (patchWidY <= 0.0) patchWidY = 0.0001;
00686
00687
00688
00689 illumBox = new Box(patchWidX, patchWidY, patchHeight);
00690 Vector center((xMax + xMin)/2., (yMax+yMin)/2., (zBot+zTop)/2.);
00691 illumBox->move(center);
00692
00693
00694 _theta = theta;
00695 _phi = phi;
00696 Vector dir(sin(_theta)*cos(_phi),sin(_theta)*sin(_phi),cos(_theta));
00697
00698 m_launchDir = (-dir).unit();
00699 m_launch = PATCHFIXED;
00700
00701 setAcceptance();
00702 }
00703
00704 void FluxSource::setLaunch(double xMax, double xMin, double yMax, double yMin,
00705 double zTop, double zBot, bool fan)
00706 {
00707
00708
00709
00710
00711
00712
00713
00714
00715 double epsilon = 1e-5;
00716
00717 sidePatch = false;
00718 fanBeam = false;
00719 double thMax = acos(_minCos);
00720 double thMin = acos(_maxCos);
00721
00722 if (zTop < zBot) {
00723 WARNING_MACRO("zTop < zBot -- SWAPPING");
00724 std::swap(zTop, zBot);
00725 }
00726
00727 patchTop = zTop;
00728 patchBottom = zBot;
00729 patchHeight = fabs(zTop - zBot);
00730 if(patchHeight < epsilon) patchHeight = 0.0;
00731
00732 if (xMax < xMin) {
00733 WARNING_MACRO("patchXmax < patchXmin in Flux -- SWAPPING");
00734 std::swap(xMax, xMin);
00735 }
00736
00737 if( yMax < yMin) {
00738 WARNING_MACRO("patchYmax < patchYmin in Flux -- SWAPPING");
00739 std::swap(yMax, yMin);
00740 }
00741
00742 patchXmax = xMax;
00743 patchXmin = xMin;
00744 patchYmax = yMax;
00745 patchYmin = yMin;
00746
00747 patchWidX = fabs(patchXmax - patchXmin);
00748 patchWidY = fabs(patchYmax - patchYmin);
00749 if(patchWidX < epsilon) patchWidX = 0.0;
00750 if(patchWidY < epsilon) patchWidY = 0.0;
00751
00752
00753 double aTop, aBot, aSide0, aSide1, aSide2, aSide3;
00754
00755
00756 if( (patchWidX == 0.0) || (patchWidY == 0.0) ) {
00757
00758 if( (patchHeight == 0.0) || ((patchWidX == 0.0) && (patchWidY == 0.0)) ) {
00759 FATAL_MACRO("zero area illumination\n");
00760 }
00761
00762
00763 sidePatch = true;
00764
00765 fanBeam = fan;
00766
00767 if( patchWidY == 0.0) {
00768
00769 double tempY = patchYmax;
00770 patchWidY = patchWidX;
00771 patchYmax = patchXmax;
00772 patchYmin = patchXmin;
00773 patchWidX = 0.0;
00774 patchXmin = tempY;
00775 patchXmax = tempY;
00776 }
00777
00778
00779 aSide0 = patchHeight * patchWidY;
00780 aSide1 = 0.0;
00781 aSide2 = 0.0;
00782 aSide3 = 0.0;
00783 aTop = 0.0;
00784 aBot = 0.0;
00785
00786 } else {
00787
00788 aTop = patchWidX * patchWidY;
00789 aBot = patchWidX * patchWidY;
00790 aSide0 = patchHeight * patchWidY;
00791 aSide1 = patchHeight * patchWidX;
00792 aSide2 = patchHeight * patchWidY;
00793 aSide3 = patchHeight * patchWidX;
00794 }
00795
00796
00797 if( (sidePatch == true) && (fanBeam == false) ) {
00798
00799
00800 } else if ((sidePatch == true) &&
00801 ((_minPhi < (-M_PI/2.) * (1.+epsilon) ) ||
00802 (_maxPhi > (M_PI/2.) * (1.+epsilon) ) ) )
00803 {
00804
00805 _minPhi = -M_PI/2.;
00806 _maxPhi = M_PI/2.;
00807
00808 } else if (sidePatch == false) {
00809
00810 _minPhi = -M_PI;
00811 _maxPhi = M_PI;
00812 }
00813
00814
00815 double aSideTot = aSide0 + aSide1 + aSide2 + aSide3;
00816
00817 patchRange = (_minCos < 0 ? -1 : 1) * _minCos * _minCos -
00818 (_maxCos < 0 ? -1 : 1) * _maxCos * _maxCos;
00819
00820 patchOffset = (_maxCos < 0 ? -1 : 1) * _maxCos * _maxCos;
00821
00822
00823
00824 float wBot = 0.0, wTop = 0.0;
00825
00826 if (sidePatch == true) {
00827
00828 wBot = 0.0;
00829 wTop = 0.0;
00830
00831 } else {
00832
00833
00834 if ( (thMax <= M_PI / 2.) && (thMin < M_PI / 2.) ) {
00835
00836 wBot = 0.0;
00837 wTop = _maxCos * _maxCos - _minCos * _minCos;
00838
00839 if((thMax == 0) && (thMin == 0) ) wTop = 1.0;
00840
00841 } else if ( (thMax > M_PI / 2.) && (thMin < M_PI / 2.) ) {
00842
00843 wBot = _minCos * _minCos;
00844 wTop = _maxCos * _maxCos;
00845
00846 } else {
00847 wBot = _minCos * _minCos - _maxCos * _maxCos;
00848 wTop = 0.0;
00849 if ( (thMax == M_PI) && (thMin == M_PI) ) wBot = 1.0;
00850 }
00851 }
00852
00853
00854
00855
00856
00857 float wSide;
00858
00859 if(sidePatch == true) {
00860 wSide = 1.0;
00861 } else {
00862 wSide = ( (thMax - thMin) - 0.5 * ( sin(2. * thMax) - sin(2. * thMin) ) )
00863 / M_PI;
00864 }
00865
00866 Fratio = wSide * aSideTot / (wSide * aSideTot + wTop * aTop + wBot * aBot);
00867
00868
00869
00870
00871
00872 m_launch = SURFACE;
00873 setAcceptance();
00874 }
00875
00876 void FluxSource::getSurfacePosDir() {
00877
00878
00879
00880
00881
00882
00883
00884
00885
00886
00887
00888
00889
00890
00891
00892
00893
00894
00895
00896
00897
00898
00899 double xInc, yInc, zInc;
00900 double cosTh, sinTh, phi;
00901 int sideNum;
00902 if (RandFlat::shoot() < Fratio) {
00903 double cosE, sinE;
00904
00905 if ( (sidePatch == true) && (fanBeam == false) ) {
00906
00907
00908
00909 double randNum = RandFlat::shoot() * patchRange + patchOffset;
00910 cosE = ( (randNum < 0) ? -1 : 1) * sqrt( fabs (randNum) );
00911 sinE = sqrt( 1 - cosE * cosE);
00912
00913
00914 double Xi = RandFlat::shoot(0., 2*M_PI);
00915
00916 cosTh = sinE * sin(Xi);
00917 sinTh = sqrt(1 - cosTh * cosTh);
00918
00919 double anySidePhi = (Xi < 0 ? -1 : 1) * acos(cosE / sinTh);
00920 phi = anySidePhi;
00921
00922
00923 sideNum = 0;
00924
00925 } else {
00926
00927
00928 bool PhiDONE;
00929 do {
00930 PhiDONE = false;
00931 cosE = sqrt(RandFlat::shoot());
00932
00933
00934
00935 sinE = sqrt( 1 - cosE * cosE);
00936
00937 double Xi = RandFlat::shoot(-M_PI, M_PI);
00938 cosTh = sinE * sin(Xi);
00939 sinTh = sqrt(1 - cosTh * cosTh);
00940
00941 double rand = RandFlat::shoot(-1, 1);
00942
00943 double anySidePhi = (rand < 0 ? -1 : 1) * acos(cosE / sinTh);
00944
00945 sideNum = int(4 * RandFlat::shoot());
00946 if(sidePatch == true) sideNum = 0;
00947 phi = anySidePhi + (M_PI / 2.) * sideNum;
00948
00949 if(fanBeam == true) {
00950 if ( (phi >= _minPhi) && (phi <= _maxPhi) ) PhiDONE = true;
00951 } else {
00952 PhiDONE = true;
00953 }
00954
00955 } while( (cosTh > _maxCos) || (cosTh < _minCos) || (!PhiDONE) );
00956
00957 }
00958
00959 zInc = patchBottom + patchHeight * RandFlat::shoot();
00960
00961 if ( (sideNum % 2) == 0) {
00962 if(sideNum == 0) {
00963 xInc = patchXmax;
00964 } else {
00965 xInc = patchXmin;
00966 }
00967 yInc = patchYmin + patchWidY * RandFlat::shoot();
00968 } else {
00969 xInc = patchXmin + patchWidX * RandFlat::shoot();
00970 if (sideNum == 1) {
00971 yInc = patchYmax;
00972 } else {
00973 yInc = patchYmin;
00974 }
00975 }
00976 } else {
00977
00978
00979
00980 phi = RandFlat::shoot(_minPhi, _maxPhi);
00981 double ranN = RandFlat::shoot() * patchRange + patchOffset;
00982 cosTh = (ranN > 0 ? 1 : -1) * sqrt( fabs ( ranN ) );
00983 sinTh = sqrt( 1 - cosTh * cosTh );
00984
00985 if (cosTh > 0.) {
00986 zInc = patchTop;
00987 }
00988 else {
00989 zInc = patchBottom;
00990 }
00991 xInc = patchXmin + patchWidX * RandFlat::shoot();
00992 yInc = patchYmin + patchWidY * RandFlat::shoot();
00993 }
00994
00995 Point IncPoint(xInc, yInc, zInc);
00996 m_launchPoint = IncPoint;
00997 m_launchDir = Vector( -(cos(phi) * sinTh), -(sin(phi) * sinTh), -(cosTh));
00998 }
00999
01000 void FluxSource::getGalacticDir(double l,double b){
01001 using namespace astro;
01002 SkyDir unrotated(l,b,SkyDir::GALACTIC);
01003
01004
01005
01006
01007
01008
01009
01010
01011
01012
01013
01014 Rotation celtoglast=GPS::instance()->transformCelToGlast(GPS::instance()->time() + m_interval + m_extime);
01015
01016
01017
01018 setLaunch(celtoglast*unrotated());
01019 m_launch = GALACTIC;
01020 correctForTiltAngle();
01021 }
01022
01023
01024 std::string FluxSource::title () const
01025 {
01026 std::strstream t;
01027 t << m_spectrum->title() << ", ";
01028 switch (m_launch) {
01029 case NONE:
01030 t << "range(" << _minCos << ',' << _maxCos << "), ";
01031 if( theta() == 0) break;
01032 case DIRECTION:
01033 t << "angle(" << theta()*180/M_PI << ','
01034 << phi()*180/M_PI << "), ";
01035 break;
01036 case POINT:
01037 t << "launch(" << m_launchDir << m_launchPoint << "), ";
01038 break;
01039 case SURFACE:
01040 t << "box(" << patchXmin << ',' << patchXmax << ',' << patchYmin << ','
01041 << patchYmax << ',' << patchTop << ',' << patchBottom << ") theta("
01042 << _minCos << ',' << _maxCos << "), phi(" << _minPhi << ','
01043 << _maxPhi << "), ";
01044 break;
01045 case SPECTRUM:
01046 break;
01047 case GALACTIC:
01048 break;
01049 case PATCHFIXED:
01050 t << "box(" << patchXmin << ',' << patchXmax << ',' << patchYmin
01051 << ',' << patchYmax << ',' << patchTop << ',' << patchBottom
01052 << ") theta(" << _theta << "), phi(" << _phi << "), ";
01053 }
01054 t << "flux("<< flux(0.) << ")" << '\0';
01055 std::string s(t.str());
01056 #ifdef WIN32
01057 t.freeze(false);
01058 #endif
01059 return s;
01060 }
01061
01062
01063 void FluxSource::refLaunch(LaunchType launch) {m_launch=launch;}
01064 void FluxSource::refPoint(PointType point) {m_pointtype=point;}
01065
01066 double FluxSource::calculateInterval (double time){
01067
01068 double intrval=m_spectrum->interval(time);
01069 if(intrval!=-1){m_interval = intrval;
01070 }else{
01071 m_interval = explicitInterval(time);
01072 }
01073 return m_interval;
01074 }
01075
01076
01077 double FluxSource::explicitInterval (double time)
01078 {
01079 double r = (solidAngle()*flux(time)*6.);
01080
01081 if (r == 0){ return -1.;
01082 }else{
01083 double p = RandFlat::shoot(1.);
01084 return ((-1.)*(log(1.-p))/r) ;
01085 }
01086 }
01087
01088 bool FluxSource::occluded(){
01089 double current,max,z;
01090
01091
01092
01093
01094
01095
01096 z=this->rawDir().z();
01097
01098 current=asin( fabs(this->rawDir().z()) / 1.);
01099 max = acos(-0.4)-(M_PI/2.);
01100
01101 return (m_launch == GALACTIC || m_launch == SPECGAL) && ( (current > max) && (z > 0) );
01102
01103 }
01104
01105 void FluxSource::correctForTiltAngle(){
01106
01107
01108
01109 m_correctForTilt =GPS::instance()->rockingAngleTransform(GPS::instance()->time());
01110 m_correctedDir = m_correctForTilt*m_launchDir;
01111
01112
01113 }
01114
01115 void FluxSource::spreadTheDirection(){
01116 double phi = RandFlat::shoot(M_2PI);
01117 double mcostheta = cos(m_degreespread*M_PI/180.);
01118 double costheta = RandFlat::shoot(mcostheta,1.0);
01119 Vector launchprime = m_launchDir;
01120 m_launchDir.rotate(acos(costheta) , m_launchDir.orthogonal());
01121 m_launchDir.rotate(phi,launchprime);
01122
01123 }