00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #ifdef HAVE_CONFIG_H
00029 #include <config.h>
00030 #endif
00031 #include <typeinfo>
00032 #include "GObservationRegistry.hpp"
00033 #include "GTools.hpp"
00034 #include "GModels.hpp"
00035 #include "GModelSky.hpp"
00036 #include "GModelSpatial.hpp"
00037 #include "GModelSpectral.hpp"
00038 #include "GModelTemporal.hpp"
00039 #include "GSkyRegionCircle.hpp"
00040 #include "GOptimizerPars.hpp"
00041 #include "GCTAObservation.hpp"
00042 #include "GCTAEventAtom.hpp"
00043 #include "GCTAEventCube.hpp"
00044 #include "GCTAResponseIrf.hpp"
00045 #include "GCTACubeBackground.hpp"
00046 #include "GCTAModelIrfBackground.hpp"
00047 #include "GCTAOnOffObservation.hpp"
00048
00049
00050 #ifdef _OPENMP
00051 #include <omp.h>
00052 #endif
00053
00054
00055 const GCTAOnOffObservation g_onoff_obs_cta_seed;
00056 const GObservationRegistry g_onoff_obs_cta_registry(&g_onoff_obs_cta_seed);
00057
00058
00059 #define G_RESPONSE_SET "GCTAOnOffObservation::response(GResponse&)"
00060 #define G_RESPONSE_GET "GCTAOnOffObservation::response()"
00061 #define G_WRITE "GCTAOnOffObservation::write(GXmlElement&)"
00062 #define G_READ "GCTAOnOffObservation::read(GXmlElement&)"
00063 #define G_LIKELIHOOD "GCTAOnOffObservation::likelihood(GModels&, "\
00064 "GOptimizerPars&, GMatrixSparse&, "\
00065 "GVector&, double&, double&)"
00066 #define G_SET "GCTAOnOffObservation::set(GCTAObservation&)"
00067 #define G_COMPUTE_ARF "GCTAOnOffObservation::compute_arf(GCTAObservation&)"
00068 #define G_COMPUTE_BGD "GCTAOnOffObservation::compute_bgd(GCTAObservation&)"
00069 #define G_COMPUTE_ALPHA "GCTAOnOffObservation::compute_alpha("\
00070 "GCTAObservation&)"
00071 #define G_COMPUTE_RMF "GCTAOnOffObservation::compute_rmf(GCTAObservation&)"
00072
00073
00074 const double minmod = 1.0e-100;
00075 const double minerr = 1.0e-100;
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096 GCTAOnOffObservation::GCTAOnOffObservation(void) : GObservation()
00097 {
00098
00099 init_members();
00100
00101
00102 return;
00103 }
00104
00105
00106
00107
00108
00109
00110
00111 GCTAOnOffObservation::GCTAOnOffObservation(const GCTAOnOffObservation& obs) :
00112 GObservation(obs)
00113 {
00114
00115 init_members();
00116
00117
00118 copy_members(obs);
00119
00120
00121 return;
00122 }
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140 GCTAOnOffObservation::GCTAOnOffObservation(const GCTAObservation& obs,
00141 const GEbounds& etrue,
00142 const GEbounds& ereco,
00143 const GSkyRegions& on,
00144 const GSkyRegions& off) :
00145 GObservation()
00146 {
00147
00148 init_members();
00149
00150
00151 m_on_spec = GPha(ereco);
00152 m_off_spec = GPha(ereco);
00153
00154
00155 m_arf = GArf(ereco);
00156 m_rmf = GRmf(etrue, ereco);
00157
00158
00159 m_on_regions = on;
00160 m_off_regions = off;
00161
00162
00163 set(obs);
00164
00165
00166 return;
00167 }
00168
00169
00170
00171
00172
00173 GCTAOnOffObservation::~GCTAOnOffObservation(void)
00174 {
00175
00176 free_members();
00177
00178
00179 return;
00180 }
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197 GCTAOnOffObservation& GCTAOnOffObservation::operator=(const GCTAOnOffObservation& obs)
00198 {
00199
00200 if (this != &obs) {
00201
00202
00203 this->GObservation::operator=(obs);
00204
00205
00206 free_members();
00207
00208
00209 init_members();
00210
00211
00212 copy_members(obs);
00213
00214 }
00215
00216
00217 return *this;
00218 }
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234 void GCTAOnOffObservation::clear(void)
00235 {
00236
00237 free_members();
00238
00239
00240 init_members();
00241
00242
00243 return;
00244 }
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254 GCTAOnOffObservation* GCTAOnOffObservation::clone(void) const
00255 {
00256 return new GCTAOnOffObservation(*this);
00257 }
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270 void GCTAOnOffObservation::response(const GResponse& rsp)
00271 {
00272
00273 const GCTAResponse* ptr = dynamic_cast<const GCTAResponse*>(&rsp);
00274
00275
00276 if (ptr == NULL) {
00277 std::string cls = std::string(typeid(&rsp).name());
00278 std::string msg = "Invalid response type \""+cls+"\" provided on "
00279 "input. Please specify a \"GCTAResponse\" "
00280 "as argument.";
00281 throw GException::invalid_argument(G_RESPONSE_SET, msg);
00282 }
00283
00284
00285 if (m_response != NULL) delete m_response;
00286
00287
00288 m_response = ptr->clone();
00289
00290
00291 return;
00292 }
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307 const GCTAResponse* GCTAOnOffObservation::response(void) const
00308 {
00309
00310 if (m_response == NULL) {
00311 std::string msg = "No valid response function found in CTA On/Off "
00312 "observation.\n";
00313 throw GException::invalid_value(G_RESPONSE_GET, msg);
00314 }
00315
00316
00317 return m_response;
00318 }
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339 void GCTAOnOffObservation::read(const GXmlElement& xml)
00340 {
00341
00342 clear();
00343
00344
00345 m_instrument = xml.attribute("instrument");
00346
00347
00348 std::string pha_on = gammalib::xml_get_attr(G_READ, xml, "Pha_on", "file");
00349 std::string pha_off = gammalib::xml_get_attr(G_READ, xml, "Pha_off", "file");
00350 std::string reg_on = gammalib::xml_get_attr(G_READ, xml, "Regions_on", "file");
00351 std::string reg_off = gammalib::xml_get_attr(G_READ, xml, "Regions_off", "file");
00352 std::string arf = gammalib::xml_get_attr(G_READ, xml, "Arf", "file");
00353 std::string rmf = gammalib::xml_get_attr(G_READ, xml, "Rmf", "file");
00354
00355
00356 pha_on = gammalib::xml_file_expand(xml, pha_on);
00357 pha_off = gammalib::xml_file_expand(xml, pha_off);
00358 reg_on = gammalib::xml_file_expand(xml, reg_on);
00359 reg_off = gammalib::xml_file_expand(xml, reg_off);
00360 arf = gammalib::xml_file_expand(xml, arf);
00361 rmf = gammalib::xml_file_expand(xml, rmf);
00362
00363
00364 m_on_spec.load(pha_on);
00365 m_off_spec.load(pha_off);
00366 m_on_regions.load(reg_on);
00367 m_off_regions.load(reg_off);
00368 m_arf.load(arf);
00369 m_rmf.load(rmf);
00370
00371
00372 return;
00373 }
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395 void GCTAOnOffObservation::write(GXmlElement& xml) const
00396 {
00397
00398 GXmlElement* par;
00399
00400
00401 par = gammalib::xml_need_par(G_WRITE, xml, "Pha_on");
00402 par->attribute("file", gammalib::xml_file_reduce(xml, m_on_spec.filename()));
00403
00404
00405 par = gammalib::xml_need_par(G_WRITE, xml, "Pha_off");
00406 par->attribute("file", gammalib::xml_file_reduce(xml, m_off_spec.filename()));
00407
00408
00409 par = gammalib::xml_need_par(G_WRITE, xml, "Regions_on");
00410 par->attribute("file", gammalib::xml_file_reduce(xml, m_on_regions.filename()));
00411
00412
00413 par = gammalib::xml_need_par(G_WRITE, xml, "Regions_off");
00414 par->attribute("file", gammalib::xml_file_reduce(xml, m_off_regions.filename()));
00415
00416
00417 par = gammalib::xml_need_par(G_WRITE, xml, "Arf");
00418 par->attribute("file", gammalib::xml_file_reduce(xml, m_arf.filename()));
00419
00420
00421 par = gammalib::xml_need_par(G_WRITE, xml, "Rmf");
00422 par->attribute("file", gammalib::xml_file_reduce(xml, m_rmf.filename()));
00423
00424
00425 return;
00426 }
00427
00428
00429
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458
00459
00460
00461
00462
00463
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475
00476
00477
00478
00479
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490
00491
00492
00493
00494
00495
00496
00497
00498
00499
00500
00501
00502
00503
00504
00505
00506
00507
00508
00509
00510
00511
00512
00513
00514
00515
00516
00517
00518
00519
00520
00521
00522
00523
00524
00525
00526
00527
00528
00529
00530 double GCTAOnOffObservation::likelihood(const GModels& models,
00531 GVector* gradient,
00532 GMatrixSparse* curvature,
00533 double* npred) const
00534 {
00535
00536 #if defined(G_LIKELIHOOD_DEBUG)
00537 #ifdef _OPENMP
00538 double t_start = omp_get_wtime();
00539 #else
00540 clock_t t_start = clock();
00541 #endif
00542 #endif
00543
00544
00545 #if defined(G_LIKELIHOOD_DEBUG)
00546 int n_bins = m_on_spec.size();
00547 int n_used = 0;
00548 int n_small_model = 0;
00549 int n_zero_data = 0;
00550 double sum_data = 0.0;
00551 double sum_model = 0.0;
00552 double init_npred = *npred;
00553 #endif
00554
00555
00556 double value = 0.0;
00557
00558
00559 int npars = models.npars();
00560
00561
00562 GVector sky_grad(npars);
00563 GVector bgd_grad(npars);
00564
00565
00566 GVector colvar(npars);
00567
00568
00569 const std::vector<double>& alpha = m_arf["ALPHA"];
00570
00571
00572 if (npars > 0) {
00573
00574
00575 for (int i = 0; i < m_on_spec.size(); ++i) {
00576
00577
00578 for (int j = 0; j < npars; ++j) {
00579 sky_grad[j] = 0.0;
00580 bgd_grad[j] = 0.0;
00581 }
00582
00583
00584 double non = m_on_spec[i];
00585 double noff = m_off_spec[i];
00586
00587
00588
00589 double ngam = N_gamma(models, i, &sky_grad);
00590 double nbgd = N_bgd(models, i, &bgd_grad);
00591
00592
00593 double nonpred = ngam + alpha[i] * nbgd;
00594 if ((nbgd <= minmod) || (nonpred <= minmod)) {
00595 #if defined(G_LIKELIHOOD_DEBUG)
00596 n_small_model++;
00597 #endif
00598 continue;
00599 }
00600
00601
00602
00603
00604 value += -non * log(nonpred) + nonpred - noff * log(nbgd) + nbgd;
00605 *npred += nonpred;
00606
00607
00608 #if defined(G_LIKELIHOOD_DEBUG)
00609 n_used++;
00610 sum_data += non;
00611 sum_model += nonpred;
00612 #endif
00613
00614
00615 double fa = non/nonpred;
00616 double fb = fa/nonpred;
00617 double fc = alpha[i] * fb;
00618 double fd = fc * alpha[i] + noff/(nbgd*nbgd);
00619 double sky_factor = 1.0 - fa;
00620 double bgd_factor = 1.0 + alpha[i] - alpha[i] * fa - noff/nbgd;
00621
00622
00623 for (int j = 0; j < npars; ++j) {
00624
00625
00626
00627
00628 if (sky_grad[j] != 0.0 && !gammalib::is_infinite(sky_grad[j])) {
00629
00630
00631 (*gradient)[j] += sky_factor * sky_grad[j];
00632
00633
00634 for (int k = 0; k < npars; ++k) {
00635
00636
00637
00638
00639 if (sky_grad[k] != 0.0 &&
00640 !gammalib::is_infinite(sky_grad[k])) {
00641 colvar[k] = sky_grad[j] * sky_grad[k] * fb;
00642 }
00643
00644
00645
00646
00647
00648 else if (bgd_grad[k] != 0.0 &&
00649 !gammalib::is_infinite(bgd_grad[k])) {
00650 colvar[k] = sky_grad[j] * bgd_grad[k] * fc;
00651 }
00652
00653
00654 else {
00655 colvar[k] = 0.0;
00656 }
00657
00658 }
00659
00660
00661 curvature->add_to_column(j, colvar);
00662
00663 }
00664
00665
00666
00667
00668
00669 else if (bgd_grad[j] != 0.0 &&
00670 !gammalib::is_infinite(bgd_grad[j])) {
00671
00672
00673 (*gradient)[j] += bgd_factor * bgd_grad[j];
00674
00675
00676 for (int k = 0; k < npars; ++k) {
00677
00678
00679
00680
00681 if (sky_grad[k] != 0.0 &&
00682 !gammalib::is_infinite(sky_grad[k])) {
00683 colvar[k] = bgd_grad[j] * sky_grad[k] * fc;
00684 }
00685
00686
00687
00688
00689 else if (bgd_grad[k] != 0.0 &&
00690 !gammalib::is_infinite(bgd_grad[k])) {
00691 colvar[k] = bgd_grad[j] * bgd_grad[k] * fd;
00692 }
00693
00694
00695 else {
00696 colvar[k] = 0.0;
00697 }
00698
00699 }
00700
00701
00702 curvature->add_to_column(j, colvar);
00703
00704 }
00705
00706 }
00707
00708 }
00709
00710 }
00711
00712
00713 else {
00714 std::string msg ="No model parameter for the computation of the "
00715 "likelihood in observation \""+this->name()+
00716 "\" (ID "+this->id()+").\n";
00717 throw GException::invalid_value(G_LIKELIHOOD, msg);
00718 }
00719
00720
00721 #if defined(G_LIKELIHOOD_DEBUG)
00722 std::cout << "Number of parameters: " << npars << std::endl;
00723 std::cout << "Number of bins: " << n_bins << std::endl;
00724 std::cout << "Number of bins used for computation: " << n_used << std::endl;
00725 std::cout << "Number of bins excluded due to small model: ";
00726 std::cout << n_small_model << std::endl;
00727 std::cout << "Number of bins with zero data: " << n_zero_data << std::endl;
00728 std::cout << "Sum of data (On): " << sum_data << std::endl;
00729 std::cout << "Sum of model (On): " << sum_model << std::endl;
00730 std::cout << "Statistics: " << value << std::endl;
00731 #endif
00732
00733
00734 #if defined(G_LIKELIHOOD_DEBUG)
00735 std::cout << *gradient << std::endl;
00736 std::cout << *curvature << std::endl;
00737 #endif
00738
00739
00740 #if defined(G_LIKELIHOOD_DEBUG)
00741 #ifdef _OPENMP
00742 double t_elapse = omp_get_wtime()-t_start;
00743 #else
00744 double t_elapse = (double)(clock() - t_start) / (double)CLOCKS_PER_SEC;
00745 #endif
00746 std::cout << "GCTAOnOffObservation::optimizer::likelihood: CPU usage = "
00747 << t_elapse << " sec" << std::endl;
00748 #endif
00749
00750
00751 return value;
00752 }
00753
00754
00755
00756
00757
00758
00759
00760 std::string GCTAOnOffObservation::print(const GChatter& chatter) const
00761 {
00762
00763 std::string result;
00764
00765
00766 if (chatter != SILENT) {
00767
00768
00769 result.append("=== GCTAOnOffObservation ===");
00770
00771
00772 result.append("\n"+gammalib::parformat("Name")+m_name);
00773 result.append("\n"+gammalib::parformat("Identifier")+m_id);
00774
00775
00776 result.append("\n"+m_on_spec.print(gammalib::reduce(chatter)));
00777 result.append("\n"+m_off_spec.print(gammalib::reduce(chatter)));
00778 result.append("\n"+m_arf.print(gammalib::reduce(chatter)));
00779 result.append("\n"+m_rmf.print(gammalib::reduce(chatter)));
00780
00781
00782 result.append("\n"+m_on_regions.print(gammalib::reduce(chatter)));
00783 result.append("\n"+m_off_regions.print(gammalib::reduce(chatter)));
00784 }
00785
00786
00787 return result;
00788 }
00789
00790
00791
00792
00793
00794
00795
00796
00797
00798
00799
00800 void GCTAOnOffObservation::init_members(void)
00801 {
00802
00803 m_instrument = "CTAOnOff";
00804 m_response = NULL;
00805 m_ontime = 0.0;
00806 m_livetime = 0.0;
00807 m_deadc = 1.0;
00808 m_on_spec.clear();
00809 m_off_spec.clear();
00810 m_arf.clear();
00811 m_rmf.clear();
00812 m_on_regions.clear();
00813 m_off_regions.clear();
00814
00815
00816 return;
00817 }
00818
00819
00820
00821
00822
00823
00824
00825 void GCTAOnOffObservation::copy_members(const GCTAOnOffObservation& obs)
00826 {
00827
00828 m_instrument = obs.m_instrument;
00829 m_ontime = obs.m_ontime;
00830 m_livetime = obs.m_livetime;
00831 m_deadc = obs.m_deadc;
00832 m_on_spec = obs.m_on_spec;
00833 m_off_spec = obs.m_off_spec;
00834 m_arf = obs.m_arf;
00835 m_rmf = obs.m_rmf;
00836 m_on_regions = obs.m_on_regions;
00837 m_off_regions = obs.m_off_regions;
00838
00839
00840 m_response = (obs.m_response != NULL) ? obs.m_response->clone() : NULL;
00841
00842
00843 return;
00844 }
00845
00846
00847
00848
00849
00850
00851 void GCTAOnOffObservation::free_members(void)
00852 {
00853
00854 return;
00855 }
00856
00857
00858
00859
00860
00861
00862
00863
00864
00865
00866
00867
00868
00869
00870 void GCTAOnOffObservation::set(const GCTAObservation& obs)
00871 {
00872
00873 const GCTAEventList* events = dynamic_cast<const GCTAEventList*>(obs.events());
00874 if (events == NULL) {
00875 std::string msg = "No event list found in CTA observation \""+
00876 obs.name()+"\" (ID="+obs.id()+"). ON/OFF observation "
00877 "can only be filled from event list.";
00878 throw GException::invalid_value(G_SET, msg);
00879 }
00880
00881
00882 for (int i = 0; i < events->size(); ++i) {
00883
00884
00885 const GCTAEventAtom* atom = (*events)[i];
00886 GSkyDir dir = atom->dir().dir();
00887
00888
00889 if (m_on_regions.contains(dir)) {
00890 m_on_spec.fill(atom->energy());
00891 }
00892 if (m_off_regions.contains(dir)) {
00893 m_off_spec.fill(atom->energy());
00894 }
00895
00896 }
00897
00898
00899 m_on_spec.exposure(obs.livetime());
00900 m_off_spec.exposure(obs.livetime());
00901
00902
00903 m_ontime = obs.ontime();
00904 m_livetime = obs.livetime();
00905 m_deadc = obs.deadc();
00906
00907
00908 compute_arf(obs);
00909 compute_bgd(obs);
00910 compute_alpha(obs);
00911 compute_rmf(obs);
00912
00913
00914 return;
00915 }
00916
00917
00918
00919
00920
00921
00922
00923
00924
00925
00926
00927
00928
00929
00930 void GCTAOnOffObservation::compute_arf(const GCTAObservation& obs)
00931 {
00932
00933 GEbounds ereco = m_arf.ebounds();
00934 int nreco = ereco.size();
00935
00936
00937 if (nreco > 0) {
00938
00939
00940 const GCTAResponseIrf* response =
00941 dynamic_cast<const GCTAResponseIrf*>(obs.response());
00942 if (response == NULL) {
00943 std::string msg = "Response in CTA observation \""+obs.name()+"\" "
00944 "(ID="+obs.id()+") is not of the GCTAResponseIrf "
00945 "type.";
00946 throw GException::invalid_value(G_COMPUTE_ARF, msg);
00947 }
00948
00949
00950 GCTAPointing obspnt = obs.pointing();
00951 GSkyDir obsdir = obspnt.dir();
00952 double zenith = obspnt.zenith();
00953 double azimuth = obspnt.azimuth();
00954
00955
00956 for (int i = 0; i < nreco; ++i) {
00957
00958
00959 double logEreco = ereco.elogmean(i).log10TeV();
00960
00961
00962 m_arf[i] = 0.0;
00963
00964
00965 for (int m = 0; m < m_on_regions.size(); ++m) {
00966
00967
00968 const GSkyRegionCircle* skyreg =
00969 dynamic_cast<const GSkyRegionCircle*>(m_on_regions[m]);
00970 if (skyreg != NULL) {
00971
00972
00973 GSkyDir centre(skyreg->centre());
00974
00975
00976 double theta = obsdir.dist(centre);
00977 double phi = obsdir.posang(centre);
00978
00979
00980 m_arf[i] += response->aeff(theta,
00981 phi,
00982 zenith,
00983 azimuth,
00984 logEreco);
00985
00986 }
00987
00988 }
00989
00990 }
00991
00992 }
00993
00994
00995 return;
00996 }
00997
00998
00999
01000
01001
01002
01003
01004
01005
01006
01007
01008
01009
01010
01011
01012
01013
01014
01015 void GCTAOnOffObservation::compute_bgd(const GCTAObservation& obs)
01016 {
01017
01018 GEbounds ereco = m_arf.ebounds();
01019 int nreco = ereco.size();
01020
01021
01022 if (nreco > 0) {
01023
01024
01025 std::vector<double> background(nreco, 0.0);
01026
01027
01028 GCTAPointing obspnt = obs.pointing();
01029
01030
01031 const GCTAResponseIrf* rsp =
01032 dynamic_cast<const GCTAResponseIrf*>(obs.response());
01033 if (rsp == NULL) {
01034 std::string msg = "Specified observation does not contain an "
01035 "IRF response.\n" + obs.print();
01036 throw GException::invalid_argument(G_COMPUTE_BGD, msg);
01037 }
01038
01039
01040 const GCTABackground* bgd = rsp->background();
01041 if (bgd == NULL) {
01042 std::string msg = "Specified observation contains no "
01043 "background information.\n" + obs.print();
01044 throw GException::invalid_argument(G_COMPUTE_BGD, msg);
01045 }
01046
01047
01048 for (int m = 0; m < m_off_regions.size(); ++m) {
01049
01050
01051
01052 const GSkyRegionCircle* skyreg =
01053 dynamic_cast<const GSkyRegionCircle*>(m_off_regions[m]);
01054 if (skyreg == NULL) {
01055 continue;
01056 }
01057
01058
01059 GSkyDir centre = skyreg->centre();
01060
01061
01062 GCTAInstDir offdir = obspnt.instdir(centre);
01063
01064
01065 for (int i = 0; i < nreco; ++i) {
01066
01067
01068 double logEreco = m_on_spec.ebounds().elogmean(i).log10TeV();
01069
01070
01071 background[i] += (*bgd)(logEreco,
01072 offdir.detx(),
01073 offdir.dety()) * skyreg->solidangle();
01074
01075 }
01076
01077 }
01078
01079
01080 m_arf.append("BACKGROUND", background);
01081
01082 }
01083
01084
01085 return;
01086 }
01087
01088
01089
01090
01091
01092
01093
01094
01095
01096
01097
01098
01099
01100
01101
01102
01103
01104
01105 void GCTAOnOffObservation::compute_alpha(const GCTAObservation& obs)
01106 {
01107
01108 GEbounds ereco = m_arf.ebounds();
01109 int nreco = ereco.size();
01110
01111
01112 if (nreco > 0) {
01113
01114
01115 std::vector<double> alpha(nreco, 0.0);
01116
01117
01118 const GCTAResponseIrf* response =
01119 dynamic_cast<const GCTAResponseIrf*>(obs.response());
01120 if (response == NULL) {
01121 std::string msg = "Response in CTA observation \""+obs.name()+"\" "
01122 "(ID="+obs.id()+") is not of the GCTAResponseIrf "
01123 "type.";
01124 throw GException::invalid_value(G_COMPUTE_ALPHA, msg);
01125 }
01126
01127
01128 GCTAPointing obspnt = obs.pointing();
01129 GSkyDir obsdir = obspnt.dir();
01130
01131
01132 for (int i = 0; i < nreco; ++i) {
01133
01134
01135 double logEreco = ereco.elogmean(i).log10TeV();
01136
01137
01138 double aon(0.0);
01139 double aoff(0.0);
01140
01141
01142 for (int m = 0; m < m_on_regions.size(); ++m) {
01143
01144
01145 const GSkyRegionCircle* skyreg =
01146 dynamic_cast<const GSkyRegionCircle*>(m_on_regions[m]);
01147 if (skyreg != NULL) {
01148
01149
01150 GSkyDir centreg = skyreg->centre();
01151
01152
01153 GCTAInstDir instdir(obspnt.instdir(centreg));
01154
01155
01156 aon += (*response->background())(logEreco,
01157 instdir.detx(),
01158 instdir.dety()) *
01159 skyreg->solidangle();
01160
01161 }
01162
01163 }
01164
01165
01166 for (int m = 0; m < m_off_regions.size(); ++m) {
01167
01168
01169 const GSkyRegionCircle* skyreg =
01170 dynamic_cast<const GSkyRegionCircle*>(m_off_regions[m]);
01171 if (skyreg != NULL) {
01172
01173
01174 GSkyDir centreg = skyreg->centre();
01175
01176
01177 GCTAInstDir instdir(obspnt.instdir(centreg));
01178
01179
01180 aoff += (*response->background())(logEreco,
01181 instdir.detx(),
01182 instdir.dety()) *
01183 skyreg->solidangle();
01184
01185 }
01186
01187 }
01188
01189
01190 if (aoff > 0.0) {
01191 alpha[i] = aon/aoff;
01192 }
01193
01194 }
01195
01196
01197 m_arf.append("ALPHA", alpha);
01198
01199 }
01200
01201
01202 return;
01203 }
01204
01205
01206
01207
01208
01209
01210
01211
01212
01213
01214
01215
01216
01217
01218
01219
01220
01221 void GCTAOnOffObservation::compute_rmf(const GCTAObservation& obs)
01222 {
01223
01224 GEbounds etrue = m_rmf.etrue();
01225 GEbounds ereco = m_rmf.emeasured();
01226 int ntrue = etrue.size();
01227 int nreco = ereco.size();
01228
01229
01230 if (ntrue > 0 && nreco > 0) {
01231
01232
01233 const GCTAResponseIrf* response =
01234 dynamic_cast<const GCTAResponseIrf*>(obs.response());
01235 if (response == NULL) {
01236 std::string msg = "Response in CTA observation \""+obs.name()+"\" "
01237 "(ID="+obs.id()+") is not of the GCTAResponseIrf "
01238 "type.";
01239 throw GException::invalid_value(G_COMPUTE_RMF, msg);
01240 }
01241
01242
01243 GCTAPointing obspnt = obs.pointing();
01244 GSkyDir obsdir = obspnt.dir();
01245 double zenith = obspnt.zenith();
01246 double azimuth = obspnt.azimuth();
01247
01248
01249 for (int ireco = 0; ireco < nreco; ++ireco) {
01250
01251
01252 double logEreco = ereco.elogmean(ireco).log10TeV();
01253
01254
01255 for (int itrue = 0; itrue < ntrue; ++itrue) {
01256
01257
01258 m_rmf(itrue, ireco) = 0.0;
01259
01260
01261 double logEtrue = etrue.elogmean(itrue).log10TeV();
01262 double weight = 0.0;
01263
01264
01265 for (int m = 0; m < m_on_regions.size(); ++m) {
01266
01267
01268 const GSkyRegionCircle* skyreg =
01269 dynamic_cast<const GSkyRegionCircle*>(m_on_regions[m]);
01270 if (skyreg == NULL) {
01271 continue;
01272 }
01273
01274
01275 GSkyDir centreg(skyreg->centre());
01276
01277
01278 double theta = obsdir.dist(centreg);
01279 double phi = obsdir.posang(centreg);
01280
01281
01282 double aeff = response->aeff(theta,
01283 phi,
01284 zenith,
01285 azimuth,
01286 logEreco);
01287
01288
01289 weight += aeff;
01290 m_rmf(itrue, ireco) += response->edisp(ereco.elogmean(ireco),
01291 theta,
01292 phi,
01293 zenith,
01294 azimuth,
01295 logEtrue) * aeff;
01296
01297 }
01298
01299
01300 if (weight > 0.0) {
01301 m_rmf(itrue, ireco) /= weight;
01302 }
01303
01304 }
01305
01306 }
01307
01308 }
01309
01310
01311 return;
01312 }
01313
01314
01315
01316
01317
01318
01319
01320
01321
01322
01323
01324
01325
01326
01327
01328
01329
01330
01331
01332
01333
01334
01335
01336
01337
01338 double GCTAOnOffObservation::N_gamma(const GModels& models,
01339 const int& ibin,
01340 GVector* grad) const
01341 {
01342
01343 int npars = models.npars();
01344
01345
01346 double value = 0.0;
01347 for (int i = 0; i < npars; ++i) {
01348 (*grad)[i] = 0.0;
01349 }
01350
01351
01352 if ((ibin >= 0) && (ibin < m_on_spec.size()) && (npars > 0)) {
01353
01354
01355 int ipar = 0;
01356
01357
01358 const GEnergy emin = m_on_spec.ebounds().emin(ibin);
01359 const GEnergy emax = m_on_spec.ebounds().emax(ibin);
01360 const GEnergy emean = m_on_spec.ebounds().elogmean(ibin);
01361 const double ewidth = m_on_spec.ebounds().ewidth(ibin).MeV();
01362
01363
01364 double exposure = m_on_spec.exposure();
01365 double norm_flux = m_arf[ibin] * exposure;
01366 double norm_grad = norm_flux * ewidth;
01367
01368
01369 for (int j = 0; j < models.size(); ++j) {
01370
01371
01372 const GModel* mptr = models[j];
01373 if (mptr == NULL) {
01374 continue;
01375 }
01376
01377
01378
01379 if (!mptr->is_valid(instrument(), id())) {
01380 ipar += mptr->size();
01381 continue;
01382 }
01383
01384
01385 const GModelSky* sky = dynamic_cast<const GModelSky*>(mptr);
01386 if (sky == NULL) {
01387 ipar += mptr->size();
01388 continue;
01389 }
01390
01391
01392 GModelSpatial* spatial = sky->spatial();
01393 if (spatial != NULL) {
01394 ipar += spatial->size();
01395 }
01396
01397
01398 GModelSpectral* spectral = sky->spectral();
01399 if (spectral != NULL) {
01400
01401
01402
01403
01404
01405 value += spectral->flux(emin, emax) * norm_flux;
01406
01407
01408
01409
01410 spectral->eval(emean, GTime(), true);
01411
01412
01413 for (int k = 0; k < spectral->size(); ++k, ++ipar) {
01414 GModelPar& par = (*spectral)[k];
01415 if (par.is_free() && ipar < npars) {
01416 (*grad)[ipar] = par.factor_gradient() * norm_grad;
01417 }
01418 }
01419
01420 }
01421
01422
01423 GModelTemporal* temporal = sky->temporal();
01424 if (temporal != NULL) {
01425 ipar += temporal->size();
01426 }
01427
01428 }
01429
01430 }
01431
01432
01433 return value;
01434 }
01435
01436
01437
01438
01439
01440
01441
01442
01443
01444
01445
01446
01447
01448
01449
01450
01451
01452
01453
01454
01455
01456
01457
01458
01459
01460
01461
01462
01463 double GCTAOnOffObservation::N_bgd(const GModels& models,
01464 const int& ibin,
01465 GVector* grad) const
01466 {
01467
01468 int npars = models.npars();
01469
01470
01471 double value = 0.0;
01472 for (int i = 0; i < npars; ++i) {
01473 (*grad)[i] = 0.0;
01474 }
01475
01476
01477 if ((ibin >= 0) && (ibin < m_off_spec.size()) && (npars > 0)) {
01478
01479
01480 int ipar = 0;
01481
01482
01483 const std::vector<double>& background = m_arf["BACKGROUND"];
01484
01485
01486 const GEnergy emean = m_off_spec.ebounds().elogmean(ibin);
01487 const double ewidth = m_off_spec.ebounds().ewidth(ibin).MeV();
01488
01489
01490 double exposure = m_off_spec.exposure();
01491 double norm = background[ibin] * exposure * ewidth;
01492
01493
01494 for (int j = 0; j < models.size(); ++j) {
01495
01496
01497 const GModel* mptr = models[j];
01498 if (mptr == NULL) {
01499 continue;
01500 }
01501
01502
01503
01504 if (!mptr->is_valid(this->instrument(), this->id())) {
01505 ipar += mptr->size();
01506 continue;
01507 }
01508
01509
01510 const GCTAModelIrfBackground* bgd =
01511 dynamic_cast<const GCTAModelIrfBackground*>(mptr);
01512 if (bgd == NULL) {
01513 ipar += mptr->size();
01514 continue;
01515 }
01516
01517
01518 GModelSpectral* spectral = bgd->spectral();
01519 if (spectral != NULL) {
01520
01521
01522
01523
01524
01525
01526
01527 value += spectral->eval(emean, GTime(), true) * norm;
01528
01529
01530
01531 for (int k = 0; k < spectral->size(); ++k, ++ipar) {
01532 GModelPar& par = (*spectral)[k];
01533 if (par.is_free() && ipar < npars) {
01534 (*grad)[ipar] += par.factor_gradient() * norm;
01535 }
01536 }
01537
01538 }
01539
01540
01541 GModelTemporal* temporal = bgd->temporal();
01542 if (temporal != NULL) {
01543 ipar += temporal->size();
01544 }
01545
01546 }
01547
01548 }
01549
01550
01551 return value;
01552 }