Commit f1ce5f252cfe20e6b3ab286362f4784b98a43831
1 parent
58ac71c8
Introduce energy slices in ctobssim to accelerate computations, in particular at low energies.
Showing
5 changed files
with
517 additions
and
247 deletions
ChangeLog
| 1 | -2016-02-11 Juergen Knoedlseder <jurgen.knodlseder@irap.omp.eu> | 1 | +2016-02-17 Juergen Knoedlseder <jurgen.knodlseder@irap.omp.eu> |
| 2 | 2 | ||
| 3 | * Version 1.1.0 released | 3 | * Version 1.1.0 released |
| 4 | ======================== | 4 | ======================== |
| 5 | 5 | ||
| 6 | + Subdivide simulation energy range in ctobssim (#1673) | ||
| 6 | Delete existing events before simulation in ctobssim (#1663) | 7 | Delete existing events before simulation in ctobssim (#1663) |
| 7 | Add csiactcopy script (#1661) | 8 | Add csiactcopy script (#1661) |
| 8 | ctselect allows usage of non-default events and GTI extensions (#1598) | 9 | ctselect allows usage of non-default events and GTI extensions (#1598) |
NEWS
| @@ -2,7 +2,7 @@ New Features and Important Changes in ctools 1.1.0 | @@ -2,7 +2,7 @@ New Features and Important Changes in ctools 1.1.0 | ||
| 2 | 2 | ||
| 3 | Author(s) : Juergen Knoedlseder | 3 | Author(s) : Juergen Knoedlseder |
| 4 | 4 | ||
| 5 | -11 February 2016 | 5 | +17 February 2016 |
| 6 | 6 | ||
| 7 | 7 | ||
| 8 | 1. Introduction | 8 | 1. Introduction |
| @@ -28,6 +28,16 @@ None | @@ -28,6 +28,16 @@ None | ||
| 28 | 28 | ||
| 29 | 5. ctobssim - CTA observation simulation | 29 | 5. ctobssim - CTA observation simulation |
| 30 | ---------------------------------------- | 30 | ---------------------------------------- |
| 31 | +The simulation energy range is subdivided internally to avoid having a too | ||
| 32 | +large difference between simulation area and effective area. Before, there | ||
| 33 | +was a simulation area of 19634954 m^2 that was applied to all energies, which | ||
| 34 | +led to the simulation of a huge number of low energy photons that were thrown | ||
| 35 | +away later due to the small effective area. Now, the energy range is subdivided | ||
| 36 | +(controlled using the "eslices" parameter), and for each energy range, the | ||
| 37 | +simulation area is computed from the maximum effective area in that energy | ||
| 38 | +range multiplied by a security factor of 2. This leads to a much more efficient | ||
| 39 | +simulation of low-energy events (#1673). | ||
| 40 | + | ||
| 31 | Any existing events in an event list are now removed before starting the | 41 | Any existing events in an event list are now removed before starting the |
| 32 | simulation to enable providing an existing event file on input from which | 42 | simulation to enable providing an existing event file on input from which |
| 33 | only the observation attributes are extracted (for example GTI, ROI, energy | 43 | only the observation attributes are extracted (for example GTI, ROI, energy |
src/ctobssim/ctobssim.cpp
| @@ -29,6 +29,7 @@ | @@ -29,6 +29,7 @@ | ||
| 29 | #include <config.h> | 29 | #include <config.h> |
| 30 | #endif | 30 | #endif |
| 31 | #include <cstdio> | 31 | #include <cstdio> |
| 32 | +#include <typeinfo> | ||
| 32 | #include "ctobssim.hpp" | 33 | #include "ctobssim.hpp" |
| 33 | #include "GTools.hpp" | 34 | #include "GTools.hpp" |
| 34 | 35 | ||
| @@ -36,6 +37,12 @@ | @@ -36,6 +37,12 @@ | ||
| 36 | #define G_GET_PARAMETERS "ctobssim::get_parameters()" | 37 | #define G_GET_PARAMETERS "ctobssim::get_parameters()" |
| 37 | #define G_SIMULATE_SOURCE "ctobssim::simulate_source(GCTAObservation*, "\ | 38 | #define G_SIMULATE_SOURCE "ctobssim::simulate_source(GCTAObservation*, "\ |
| 38 | "GModels&, GRan&, GLog*)" | 39 | "GModels&, GRan&, GLog*)" |
| 40 | +#define G_SIMULATE_INTERVAL "ctobssim::simulate_interval(GCTAObservation*"\ | ||
| 41 | + ", GCTAEventList*, GCTAResponseIrf*, GModels&, GTime&"\ | ||
| 42 | + ", GTime&, GEnergy&, GEnergy&, GSkyDir&, double&"\ | ||
| 43 | + ", double&, GRan&, GLog*, int&)" | ||
| 44 | +#define G_GET_AREA "ctobssim::get_area(GCTAObservation* obs, GEnergy&, "\ | ||
| 45 | + "GEnergy&)" | ||
| 39 | 46 | ||
| 40 | /* __ Constants __________________________________________________________ */ | 47 | /* __ Constants __________________________________________________________ */ |
| 41 | const double g_roi_margin = 0.5; //!< Simulation radius margin (degrees) | 48 | const double g_roi_margin = 0.5; //!< Simulation radius margin (degrees) |
| @@ -382,7 +389,7 @@ void ctobssim::run(void) | @@ -382,7 +389,7 @@ void ctobssim::run(void) | ||
| 382 | simulate_background(&obs_clone, models, m_rans[i], &wrklog); | 389 | simulate_background(&obs_clone, models, m_rans[i], &wrklog); |
| 383 | 390 | ||
| 384 | // Dump simulation results | 391 | // Dump simulation results |
| 385 | - if (logNormal()) { | 392 | + if (logTerse()) { |
| 386 | wrklog << gammalib::parformat("MC events"); | 393 | wrklog << gammalib::parformat("MC events"); |
| 387 | wrklog << obs_clone.events()->size() - events_before; | 394 | wrklog << obs_clone.events()->size() - events_before; |
| 388 | wrklog << " (all models)"; | 395 | wrklog << " (all models)"; |
| @@ -512,6 +519,7 @@ void ctobssim::init_members(void) | @@ -512,6 +519,7 @@ void ctobssim::init_members(void) | ||
| 512 | m_outevents.clear(); | 519 | m_outevents.clear(); |
| 513 | m_prefix.clear(); | 520 | m_prefix.clear(); |
| 514 | m_seed = 1; | 521 | m_seed = 1; |
| 522 | + m_eslices = 10; | ||
| 515 | m_apply_edisp = false; | 523 | m_apply_edisp = false; |
| 516 | m_max_rate = 1.0e6; | 524 | m_max_rate = 1.0e6; |
| 517 | 525 | ||
| @@ -521,8 +529,7 @@ void ctobssim::init_members(void) | @@ -521,8 +529,7 @@ void ctobssim::init_members(void) | ||
| 521 | m_save_and_dispose = false; | 529 | m_save_and_dispose = false; |
| 522 | 530 | ||
| 523 | // Set fixed parameters | 531 | // Set fixed parameters |
| 524 | - m_area = 19634954.0 * 1.0e4; //!< pi*(2500^2) m^2 | ||
| 525 | - m_max_photons = 1000000; //!< Maximum number of photons / time slice | 532 | + m_max_photons = 1000000; //!< Maximum number of photons / time slice |
| 526 | 533 | ||
| 527 | // Initialise first event identifier | 534 | // Initialise first event identifier |
| 528 | m_event_id = 1; | 535 | m_event_id = 1; |
| @@ -543,11 +550,11 @@ void ctobssim::copy_members(const ctobssim& app) | @@ -543,11 +550,11 @@ void ctobssim::copy_members(const ctobssim& app) | ||
| 543 | m_outevents = app.m_outevents; | 550 | m_outevents = app.m_outevents; |
| 544 | m_prefix = app.m_prefix; | 551 | m_prefix = app.m_prefix; |
| 545 | m_seed = app.m_seed; | 552 | m_seed = app.m_seed; |
| 553 | + m_eslices = app.m_eslices; | ||
| 546 | m_apply_edisp = app.m_apply_edisp; | 554 | m_apply_edisp = app.m_apply_edisp; |
| 547 | m_max_rate = app.m_max_rate; | 555 | m_max_rate = app.m_max_rate; |
| 548 | 556 | ||
| 549 | // Copy protected members | 557 | // Copy protected members |
| 550 | - m_area = app.m_area; | ||
| 551 | m_max_photons = app.m_max_photons; | 558 | m_max_photons = app.m_max_photons; |
| 552 | m_rans = app.m_rans; | 559 | m_rans = app.m_rans; |
| 553 | m_obs = app.m_obs; | 560 | m_obs = app.m_obs; |
| @@ -608,6 +615,7 @@ void ctobssim::get_parameters(void) | @@ -608,6 +615,7 @@ void ctobssim::get_parameters(void) | ||
| 608 | 615 | ||
| 609 | // Get other parameters | 616 | // Get other parameters |
| 610 | m_seed = (*this)["seed"].integer(); | 617 | m_seed = (*this)["seed"].integer(); |
| 618 | + m_eslices = (*this)["eslices"].integer(); | ||
| 611 | m_apply_edisp = (*this)["edisp"].boolean(); | 619 | m_apply_edisp = (*this)["edisp"].boolean(); |
| 612 | m_max_rate = (*this)["maxrate"].real(); | 620 | m_max_rate = (*this)["maxrate"].real(); |
| 613 | 621 | ||
| @@ -673,17 +681,29 @@ void ctobssim::get_parameters(void) | @@ -673,17 +681,29 @@ void ctobssim::get_parameters(void) | ||
| 673 | * | 681 | * |
| 674 | * @param[in] obs Pointer on CTA observation. | 682 | * @param[in] obs Pointer on CTA observation. |
| 675 | * @param[in] models Model list. | 683 | * @param[in] models Model list. |
| 676 | - * @param[in] ran Random number generator. | 684 | + * @param[in,out] ran Random number generator. |
| 677 | * @param[in] wrklog Pointer to logger. | 685 | * @param[in] wrklog Pointer to logger. |
| 678 | * | 686 | * |
| 679 | - * Simulate source events from a photon list for a given CTA observation. | ||
| 680 | - * The events are stored in as event list in the observation. | 687 | + * Simulate source events from a photon list for a given CTA observation and |
| 688 | + * all source models. The events are stored in form of an event list in the | ||
| 689 | + * observation. | ||
| 681 | * | 690 | * |
| 682 | - * This method does nothing if the observation pointer is NULL. It also | ||
| 683 | - * verifies if the observation has a valid pointing and response. | 691 | + * The method will loop over all Good Time Intervals (GTI) to perform the |
| 692 | + * simulations. Within a given GTI the requested energy range is split into | ||
| 693 | + * a number of energy slices so that the simulation area can be adapted to | ||
| 694 | + * the effective area of the instrument (this avoids simulating a large | ||
| 695 | + * number of sources photons at low energies while accepting only few of | ||
| 696 | + * them do to the small effective area). In case that the flux of a source | ||
| 697 | + * is large, the simulation may be done within time slices so that the | ||
| 698 | + * memory requirements won't get too large. | ||
| 699 | + * | ||
| 700 | + * This method does nothing if the observation pointer is NULL. It verifies | ||
| 701 | + * if the observation has a CTA IRF response. | ||
| 684 | ***************************************************************************/ | 702 | ***************************************************************************/ |
| 685 | -void ctobssim::simulate_source(GCTAObservation* obs, const GModels& models, | ||
| 686 | - GRan& ran, GLog* wrklog) | 703 | +void ctobssim::simulate_source(GCTAObservation* obs, |
| 704 | + const GModels& models, | ||
| 705 | + GRan& ran, | ||
| 706 | + GLog* wrklog) | ||
| 687 | { | 707 | { |
| 688 | // Continue only if observation pointer is valid | 708 | // Continue only if observation pointer is valid |
| 689 | if (obs != NULL) { | 709 | if (obs != NULL) { |
| @@ -693,36 +713,42 @@ void ctobssim::simulate_source(GCTAObservation* obs, const GModels& models, | @@ -693,36 +713,42 @@ void ctobssim::simulate_source(GCTAObservation* obs, const GModels& models, | ||
| 693 | wrklog = &log; | 713 | wrklog = &log; |
| 694 | } | 714 | } |
| 695 | 715 | ||
| 716 | + // Get pointer on event list | ||
| 717 | + GCTAEventList* events = static_cast<GCTAEventList*>(obs->events()); | ||
| 718 | + | ||
| 696 | // Get CTA response | 719 | // Get CTA response |
| 697 | - const GCTAResponseIrf* rsp = | ||
| 698 | - dynamic_cast<const GCTAResponseIrf*>(obs->response()); | 720 | + const GCTAResponseIrf* rsp = dynamic_cast<const GCTAResponseIrf*>(obs->response()); |
| 699 | if (rsp == NULL) { | 721 | if (rsp == NULL) { |
| 700 | - std::string msg = "Response is not an IRF response.\n" + | ||
| 701 | - obs->response()->print(); | 722 | + std::string cls = std::string(typeid(obs->response()).name()); |
| 723 | + std::string msg = "Response of type \""+cls+"\" is not a CTA " | ||
| 724 | + "IRF response. Please make sure that a CTA " | ||
| 725 | + "IRF response is contained in the CTA " | ||
| 726 | + "observation."; | ||
| 702 | throw GException::invalid_value(G_SIMULATE_SOURCE, msg); | 727 | throw GException::invalid_value(G_SIMULATE_SOURCE, msg); |
| 703 | } | 728 | } |
| 704 | 729 | ||
| 705 | - // Get pointer on event list (circumvent const correctness) | ||
| 706 | - GCTAEventList* events = | ||
| 707 | - static_cast<GCTAEventList*>(const_cast<GEvents*>(obs->events())); | ||
| 708 | - | ||
| 709 | - // Extract simulation region. | 730 | + // Extract simulation region from event list ROI |
| 710 | GSkyDir dir = events->roi().centre().dir(); | 731 | GSkyDir dir = events->roi().centre().dir(); |
| 711 | double rad = events->roi().radius() + g_roi_margin; | 732 | double rad = events->roi().radius() + g_roi_margin; |
| 712 | 733 | ||
| 713 | - // Dump simulation cone information | ||
| 714 | - if (logNormal()) { | ||
| 715 | - *wrklog << gammalib::parformat("Simulation area"); | ||
| 716 | - *wrklog << m_area << " cm2" << std::endl; | 734 | + // Determine energy boundaries for simulation |
| 735 | + GEbounds ebounds = get_ebounds(events->ebounds()); | ||
| 736 | + | ||
| 737 | + // Log simulation cone information | ||
| 738 | + if (logTerse()) { | ||
| 717 | *wrklog << gammalib::parformat("Simulation cone"); | 739 | *wrklog << gammalib::parformat("Simulation cone"); |
| 718 | *wrklog << "RA=" << dir.ra_deg() << " deg"; | 740 | *wrklog << "RA=" << dir.ra_deg() << " deg"; |
| 719 | *wrklog << ", Dec=" << dir.dec_deg() << " deg"; | 741 | *wrklog << ", Dec=" << dir.dec_deg() << " deg"; |
| 720 | - *wrklog << ", r=" << rad << " deg" << std::endl; | 742 | + *wrklog << ", radius=" << rad << " deg" << std::endl; |
| 721 | } | 743 | } |
| 722 | 744 | ||
| 723 | // Initialise indentation for logging | 745 | // Initialise indentation for logging |
| 724 | int indent = 0; | 746 | int indent = 0; |
| 725 | 747 | ||
| 748 | + // Initialise photon and event counters | ||
| 749 | + std::vector<int> nphotons(models.size(),0); | ||
| 750 | + std::vector<int> nevents(models.size(),0); | ||
| 751 | + | ||
| 726 | // Loop over all Good Time Intervals | 752 | // Loop over all Good Time Intervals |
| 727 | for (int it = 0; it < events->gti().size(); ++it) { | 753 | for (int it = 0; it < events->gti().size(); ++it) { |
| 728 | 754 | ||
| @@ -730,7 +756,8 @@ void ctobssim::simulate_source(GCTAObservation* obs, const GModels& models, | @@ -730,7 +756,8 @@ void ctobssim::simulate_source(GCTAObservation* obs, const GModels& models, | ||
| 730 | GTime tmin = events->gti().tstart(it); | 756 | GTime tmin = events->gti().tstart(it); |
| 731 | GTime tmax = events->gti().tstop(it); | 757 | GTime tmax = events->gti().tstop(it); |
| 732 | 758 | ||
| 733 | - // Dump time interval | 759 | + // Log time interval. Increment indentation if there are |
| 760 | + // several Good Time Intervals. | ||
| 734 | if (logNormal()) { | 761 | if (logNormal()) { |
| 735 | if (events->gti().size() > 1) { | 762 | if (events->gti().size() > 1) { |
| 736 | indent++; | 763 | indent++; |
| @@ -744,14 +771,14 @@ void ctobssim::simulate_source(GCTAObservation* obs, const GModels& models, | @@ -744,14 +771,14 @@ void ctobssim::simulate_source(GCTAObservation* obs, const GModels& models, | ||
| 744 | } | 771 | } |
| 745 | 772 | ||
| 746 | // Loop over all energy boundaries | 773 | // Loop over all energy boundaries |
| 747 | - for (int ie = 0; ie < events->ebounds().size(); ++ie) { | 774 | + for (int ie = 0; ie < ebounds.size(); ++ie) { |
| 748 | 775 | ||
| 749 | - // Extract energy boundaries | ||
| 750 | - GEnergy emin = events->ebounds().emin(ie); | ||
| 751 | - GEnergy emax = events->ebounds().emax(ie); | 776 | + // Set energy interval |
| 777 | + GEnergy emin = ebounds.emin(ie); | ||
| 778 | + GEnergy emax = ebounds.emax(ie); | ||
| 752 | 779 | ||
| 753 | - // Set true photon energy limits for simulation. If observation | ||
| 754 | - // has energy dispersion then add margin | 780 | + // Set true photon energy limits for simulation. If the |
| 781 | + // observation has energy dispersion then add a margin. | ||
| 755 | GEnergy e_true_min = emin; | 782 | GEnergy e_true_min = emin; |
| 756 | GEnergy e_true_max = emax; | 783 | GEnergy e_true_max = emax; |
| 757 | if (rsp->use_edisp()) { | 784 | if (rsp->use_edisp()) { |
| @@ -759,210 +786,51 @@ void ctobssim::simulate_source(GCTAObservation* obs, const GModels& models, | @@ -759,210 +786,51 @@ void ctobssim::simulate_source(GCTAObservation* obs, const GModels& models, | ||
| 759 | e_true_max = rsp->ebounds(e_true_max).emax(); | 786 | e_true_max = rsp->ebounds(e_true_max).emax(); |
| 760 | } | 787 | } |
| 761 | 788 | ||
| 762 | - // Dump energy range | 789 | + // Determine simulation area |
| 790 | + double area = get_area(obs, emin, emax); | ||
| 791 | + | ||
| 792 | + // Log energy range and simulation area | ||
| 763 | if (logNormal()) { | 793 | if (logNormal()) { |
| 764 | - if (events->ebounds().size() > 1) { | ||
| 765 | - indent++; | ||
| 766 | - wrklog->indent(indent); | ||
| 767 | - } | ||
| 768 | *wrklog << gammalib::parformat("Photon energy range", indent); | 794 | *wrklog << gammalib::parformat("Photon energy range", indent); |
| 769 | *wrklog << e_true_min << " - " << e_true_max << std::endl; | 795 | *wrklog << e_true_min << " - " << e_true_max << std::endl; |
| 770 | *wrklog << gammalib::parformat("Event energy range", indent); | 796 | *wrklog << gammalib::parformat("Event energy range", indent); |
| 771 | *wrklog << emin << " - " << emax << std::endl; | 797 | *wrklog << emin << " - " << emax << std::endl; |
| 772 | } | 798 | } |
| 773 | 799 | ||
| 774 | - // Loop over all sky models | ||
| 775 | - for (int i = 0; i < models.size(); ++i) { | ||
| 776 | - | ||
| 777 | - // Get sky model (NULL if not a sky model) | ||
| 778 | - const GModelSky* model = | ||
| 779 | - dynamic_cast<const GModelSky*>(models[i]); | ||
| 780 | - | ||
| 781 | - // If we have a sky model that applies to the present | ||
| 782 | - // observation then simulate events | ||
| 783 | - if (model != NULL && | ||
| 784 | - model->is_valid(obs->instrument(), obs->id())) { | ||
| 785 | - | ||
| 786 | - // Determine duration of a time slice by limiting the | ||
| 787 | - // number of simulated photons to m_max_photons. | ||
| 788 | - // The photon rate is estimated from the model flux | ||
| 789 | - // and used to set the duration of the time slice. | ||
| 790 | - double flux = get_model_flux(model, emin, emax, | ||
| 791 | - dir, rad, | ||
| 792 | - indent, wrklog); | ||
| 793 | - double rate = flux * m_area; | ||
| 794 | - double duration = 1800.0; // default: 1800 sec | ||
| 795 | - if (rate > 0.0) { | ||
| 796 | - duration = m_max_photons / rate; | ||
| 797 | - if (duration < 1.0) { // not <1 sec | ||
| 798 | - duration = 1.0; | ||
| 799 | - } | ||
| 800 | - else if (duration > 180000.0) { // not >50 hr | ||
| 801 | - duration = 180000.0; | ||
| 802 | - } | ||
| 803 | - } | ||
| 804 | - GTime tslice(duration, "sec"); | ||
| 805 | - | ||
| 806 | - // Skip model if photon rate is 0 | ||
| 807 | - if (rate <= 0.0) { | ||
| 808 | - continue; | ||
| 809 | - } | ||
| 810 | - | ||
| 811 | - // Dump photon rate | ||
| 812 | - if (logNormal()) { | ||
| 813 | - *wrklog << gammalib::parformat("Photon rate", indent); | ||
| 814 | - *wrklog << rate << " photons/s"; | ||
| 815 | - if (model->name().length() > 0) { | ||
| 816 | - *wrklog << " [" << model->name() << "]"; | ||
| 817 | - } | ||
| 818 | - *wrklog << std::endl; | ||
| 819 | - } | 800 | + // Increment indentation if there are several energy |
| 801 | + // boundaries | ||
| 802 | + if (logNormal()) { | ||
| 803 | + if (ebounds.size() > 1) { | ||
| 804 | + indent++; | ||
| 805 | + wrklog->indent(indent); | ||
| 806 | + } | ||
| 807 | + } | ||
| 820 | 808 | ||
| 821 | - // If photon rate exceeds the maximum photon rate | ||
| 822 | - // then throw an exception | ||
| 823 | - if (rate > m_max_rate) { | ||
| 824 | - std::string modnam = (model->name().length() > 0) ? | ||
| 825 | - model->name() : "Unknown"; | ||
| 826 | - std::string msg = "Photon rate "+ | ||
| 827 | - gammalib::str(rate)+ | ||
| 828 | - " photons/s for model \""+ | ||
| 829 | - modnam+"\" exceeds maximum" | ||
| 830 | - " allowed photon rate of "+ | ||
| 831 | - gammalib::str(m_max_rate)+ | ||
| 832 | - " photons/s. Please check" | ||
| 833 | - " the model parameters for" | ||
| 834 | - " model \""+modnam+"\" or" | ||
| 835 | - " increase the value of the" | ||
| 836 | - " hidden \"maxrate\"" | ||
| 837 | - " parameter."; | ||
| 838 | - throw GException::invalid_value(G_SIMULATE_SOURCE, msg); | ||
| 839 | - } | 809 | + // Log simulation area |
| 810 | + if (logNormal()) { | ||
| 811 | + *wrklog << gammalib::parformat("Simulation area", indent); | ||
| 812 | + *wrklog << area << " cm2" << std::endl; | ||
| 813 | + } | ||
| 840 | 814 | ||
| 841 | - // To reduce memory requirements we split long time | ||
| 842 | - // intervals into several slices. | ||
| 843 | - GTime tstart = tmin; | ||
| 844 | - GTime tstop = tstart + tslice; | ||
| 845 | - | ||
| 846 | - // Initialise cumulative photon counters | ||
| 847 | - int nphotons = 0; | ||
| 848 | - | ||
| 849 | - // Loop over time slices | ||
| 850 | - while (tstart < tmax) { | ||
| 851 | - | ||
| 852 | - // Make sure that tstop <= tmax | ||
| 853 | - if (tstop > tmax) { | ||
| 854 | - tstop = tmax; | ||
| 855 | - } | ||
| 856 | - | ||
| 857 | - // Dump time slice | ||
| 858 | - if (logExplicit()) { | ||
| 859 | - if (tmax - tmin > tslice) { | ||
| 860 | - indent++; | ||
| 861 | - wrklog->indent(indent); | ||
| 862 | - } | ||
| 863 | - *wrklog << gammalib::parformat("Time slice", indent); | ||
| 864 | - *wrklog << tstart.convert(m_cta_ref); | ||
| 865 | - *wrklog << " - "; | ||
| 866 | - *wrklog << tstop.convert(m_cta_ref); | ||
| 867 | - *wrklog << " s"; | ||
| 868 | - if (model->name().length() > 0) { | ||
| 869 | - *wrklog << " [" << model->name() << "]"; | ||
| 870 | - } | ||
| 871 | - *wrklog << std::endl; | ||
| 872 | - } | ||
| 873 | - | ||
| 874 | - // Get photons | ||
| 875 | - GPhotons photons = model->mc(m_area, dir, rad, | ||
| 876 | - e_true_min, e_true_max, | ||
| 877 | - tstart, tstop, ran); | ||
| 878 | - | ||
| 879 | - // Dump number of simulated photons | ||
| 880 | - if (logExplicit()) { | ||
| 881 | - *wrklog << gammalib::parformat("MC source photons/slice", indent); | ||
| 882 | - *wrklog << photons.size(); | ||
| 883 | - if (model->name().length() > 0) { | ||
| 884 | - *wrklog << " [" << model->name() << "]"; | ||
| 885 | - } | ||
| 886 | - *wrklog << std::endl; | ||
| 887 | - } | ||
| 888 | - | ||
| 889 | - // Simulate events from photons | ||
| 890 | - for (int i = 0; i < photons.size(); ++i) { | ||
| 891 | - | ||
| 892 | - // Increment photon counter | ||
| 893 | - nphotons++; | ||
| 894 | - | ||
| 895 | - // Simulate event. Note that this method | ||
| 896 | - // includes the deadtime correction. | ||
| 897 | - GCTAEventAtom* event = rsp->mc(m_area, | ||
| 898 | - photons[i], | ||
| 899 | - *obs, | ||
| 900 | - ran); | ||
| 901 | - | ||
| 902 | - if (event != NULL) { | ||
| 903 | - | ||
| 904 | - // Use event only if it falls within ROI | ||
| 905 | - // energy boundary and time slice | ||
| 906 | - if (events->roi().contains(*event) && | ||
| 907 | - event->energy() >= emin && | ||
| 908 | - event->energy() <= emax && | ||
| 909 | - event->time() >= tstart && | ||
| 910 | - event->time() <= tstop) { | ||
| 911 | - event->event_id(m_event_id); | ||
| 912 | - events->append(*event); | ||
| 913 | - m_event_id++; | ||
| 914 | - } | ||
| 915 | - delete event; | ||
| 916 | - } | ||
| 917 | - | ||
| 918 | - } // endfor: looped over events | ||
| 919 | - | ||
| 920 | - // Go to next time slice | ||
| 921 | - tstart = tstop; | ||
| 922 | - tstop = tstart + tslice; | ||
| 923 | - | ||
| 924 | - // Reset indentation | ||
| 925 | - if (logExplicit()) { | ||
| 926 | - if (tmax - tmin > tslice) { | ||
| 927 | - indent--; | ||
| 928 | - wrklog->indent(indent); | ||
| 929 | - } | ||
| 930 | - } | ||
| 931 | - | ||
| 932 | - } // endwhile: looped over time slices | ||
| 933 | - | ||
| 934 | - // Dump simulation results | ||
| 935 | - if (logNormal()) { | ||
| 936 | - *wrklog << gammalib::parformat("MC source photons", indent); | ||
| 937 | - *wrklog << nphotons; | ||
| 938 | - if (model->name().length() > 0) { | ||
| 939 | - *wrklog << " [" << model->name() << "]"; | ||
| 940 | - } | ||
| 941 | - *wrklog << std::endl; | ||
| 942 | - *wrklog << gammalib::parformat("MC source events", indent); | ||
| 943 | - *wrklog << events->size(); | ||
| 944 | - if (model->name().length() > 0) { | ||
| 945 | - *wrklog << " [" << model->name() << "]"; | ||
| 946 | - } | ||
| 947 | - *wrklog << std::endl; | 815 | + // Save state of event counter before doing the simulation |
| 816 | + int nevents_before = events->size(); | ||
| 948 | 817 | ||
| 949 | - } | ||
| 950 | - | ||
| 951 | - } // endif: model was a sky model | 818 | + // Simulate events for this time and energy interval |
| 819 | + simulate_interval(obs, rsp, events, models, tmin, tmax, | ||
| 820 | + e_true_min, e_true_max, dir, rad, area, | ||
| 821 | + ran, wrklog, indent, nphotons, nevents); | ||
| 952 | 822 | ||
| 953 | - } // endfor: looped over models | ||
| 954 | - | ||
| 955 | - // Dump simulation results | 823 | + // Log simulation results |
| 956 | if (logNormal()) { | 824 | if (logNormal()) { |
| 957 | *wrklog << gammalib::parformat("MC source events", indent); | 825 | *wrklog << gammalib::parformat("MC source events", indent); |
| 958 | - *wrklog << events->size(); | 826 | + *wrklog << events->size() - nevents_before; |
| 959 | *wrklog << " (all source models)"; | 827 | *wrklog << " (all source models)"; |
| 960 | *wrklog << std::endl; | 828 | *wrklog << std::endl; |
| 961 | } | 829 | } |
| 962 | 830 | ||
| 963 | - // Reset indentation | 831 | + // Reset indentation if there were several energy boundaries |
| 964 | if (logNormal()) { | 832 | if (logNormal()) { |
| 965 | - if (events->ebounds().size() > 1) { | 833 | + if (ebounds.size() > 1) { |
| 966 | indent--; | 834 | indent--; |
| 967 | wrklog->indent(indent); | 835 | wrklog->indent(indent); |
| 968 | 836 | ||
| @@ -971,7 +839,7 @@ void ctobssim::simulate_source(GCTAObservation* obs, const GModels& models, | @@ -971,7 +839,7 @@ void ctobssim::simulate_source(GCTAObservation* obs, const GModels& models, | ||
| 971 | 839 | ||
| 972 | } // endfor: looped over all energy boundaries | 840 | } // endfor: looped over all energy boundaries |
| 973 | 841 | ||
| 974 | - // Reset indentation | 842 | + // Reset indentation if there were several Good Time Intervals |
| 975 | if (logNormal()) { | 843 | if (logNormal()) { |
| 976 | if (events->gti().size() > 1) { | 844 | if (events->gti().size() > 1) { |
| 977 | indent--; | 845 | indent--; |
| @@ -984,6 +852,31 @@ void ctobssim::simulate_source(GCTAObservation* obs, const GModels& models, | @@ -984,6 +852,31 @@ void ctobssim::simulate_source(GCTAObservation* obs, const GModels& models, | ||
| 984 | // Reset indentation | 852 | // Reset indentation |
| 985 | wrklog->indent(0); | 853 | wrklog->indent(0); |
| 986 | 854 | ||
| 855 | + // Log simulation summary | ||
| 856 | + if (logTerse()) { | ||
| 857 | + for (int i = 0; i < models.size(); ++i) { | ||
| 858 | + const GModelSky* model = dynamic_cast<const GModelSky*>(models[i]); | ||
| 859 | + if (model == NULL) { | ||
| 860 | + continue; | ||
| 861 | + } | ||
| 862 | + if (!model->is_valid(obs->instrument(), obs->id())) { | ||
| 863 | + continue; | ||
| 864 | + } | ||
| 865 | + *wrklog << gammalib::parformat("MC source photons"); | ||
| 866 | + *wrklog << nphotons[i]; | ||
| 867 | + if (model->name().length() > 0) { | ||
| 868 | + *wrklog << " [" << model->name() << "]"; | ||
| 869 | + } | ||
| 870 | + *wrklog << std::endl; | ||
| 871 | + *wrklog << gammalib::parformat("MC source events"); | ||
| 872 | + *wrklog << nevents[i]; | ||
| 873 | + if (model->name().length() > 0) { | ||
| 874 | + *wrklog << " [" << model->name() << "]"; | ||
| 875 | + } | ||
| 876 | + *wrklog << std::endl; | ||
| 877 | + } | ||
| 878 | + } | ||
| 879 | + | ||
| 987 | } // endif: observation pointer was valid | 880 | } // endif: observation pointer was valid |
| 988 | 881 | ||
| 989 | // Return | 882 | // Return |
| @@ -992,6 +885,335 @@ void ctobssim::simulate_source(GCTAObservation* obs, const GModels& models, | @@ -992,6 +885,335 @@ void ctobssim::simulate_source(GCTAObservation* obs, const GModels& models, | ||
| 992 | 885 | ||
| 993 | 886 | ||
| 994 | /***********************************************************************//** | 887 | /***********************************************************************//** |
| 888 | + * @brief Simulate source events for a time and energy interval | ||
| 889 | + * | ||
| 890 | + * @param[in] obs Pointer on CTA observation. | ||
| 891 | + * @param[in] rsp Pointer on CTA IRF response. | ||
| 892 | + * @param[in,out] events Pointer on CTA event list. | ||
| 893 | + * @param[in] models Model list. | ||
| 894 | + * @param[in] tmin Start time. | ||
| 895 | + * @param[in] tmax Stop time. | ||
| 896 | + * @param[in] emin Minimum energy. | ||
| 897 | + * @param[in] emax Maximum energy. | ||
| 898 | + * @param[in] dir Simulation cone centre. | ||
| 899 | + * @param[in] rad Simulation cone radius (degrees). | ||
| 900 | + * @param[in] area Simulation area (cm^2). | ||
| 901 | + * @param[in,out] ran Random number generator. | ||
| 902 | + * @param[in] wrklog Pointer to logger. | ||
| 903 | + * @param[in,out] indent Logger indent. | ||
| 904 | + * @param[in,out] nphotons Number of photons for all models. | ||
| 905 | + * @param[in,out] nevents Number of events for all models. | ||
| 906 | + * | ||
| 907 | + * Simulate source events for a time and energy interval. | ||
| 908 | + ***************************************************************************/ | ||
| 909 | +void ctobssim::simulate_interval(GCTAObservation* obs, | ||
| 910 | + const GCTAResponseIrf* rsp, | ||
| 911 | + GCTAEventList* events, | ||
| 912 | + const GModels& models, | ||
| 913 | + const GTime& tmin, | ||
| 914 | + const GTime& tmax, | ||
| 915 | + const GEnergy& emin, | ||
| 916 | + const GEnergy& emax, | ||
| 917 | + const GSkyDir& dir, | ||
| 918 | + const double& rad, | ||
| 919 | + const double& area, | ||
| 920 | + GRan& ran, | ||
| 921 | + GLog* wrklog, | ||
| 922 | + int& indent, | ||
| 923 | + std::vector<int>& nphotons, | ||
| 924 | + std::vector<int>& nevents) | ||
| 925 | +{ | ||
| 926 | + // Loop over all models | ||
| 927 | + for (int i = 0; i < models.size(); ++i) { | ||
| 928 | + | ||
| 929 | + // Get sky model (NULL if not a sky model) | ||
| 930 | + const GModelSky* model = dynamic_cast<const GModelSky*>(models[i]); | ||
| 931 | + | ||
| 932 | + // If the model is not a sky model then skip the model | ||
| 933 | + if (model == NULL) { | ||
| 934 | + continue; | ||
| 935 | + } | ||
| 936 | + | ||
| 937 | + // If the model does not apply to the instrument and observation | ||
| 938 | + // identifier then skip the model | ||
| 939 | + if (!model->is_valid(obs->instrument(), obs->id())) { | ||
| 940 | + continue; | ||
| 941 | + } | ||
| 942 | + | ||
| 943 | + // Determine duration of a time slice by limiting the number of | ||
| 944 | + // simulated photons to m_max_photons. The photon rate is estimated | ||
| 945 | + // from the model flux and used to set the duration of the time | ||
| 946 | + // slice. | ||
| 947 | + double flux = get_model_flux(model, emin, emax, dir, rad, | ||
| 948 | + indent, wrklog); | ||
| 949 | + double rate = flux * area; | ||
| 950 | + double duration = 1800.0; // default: 1800 sec | ||
| 951 | + if (rate > 0.0) { | ||
| 952 | + duration = m_max_photons / rate; | ||
| 953 | + if (duration < 1.0) { // not <1 sec | ||
| 954 | + duration = 1.0; | ||
| 955 | + } | ||
| 956 | + else if (duration > 180000.0) { // not >50 hr | ||
| 957 | + duration = 180000.0; | ||
| 958 | + } | ||
| 959 | + } | ||
| 960 | + GTime tslice(duration, "sec"); | ||
| 961 | + | ||
| 962 | + // Skip model if photon rate is 0 | ||
| 963 | + if (rate <= 0.0) { | ||
| 964 | + continue; | ||
| 965 | + } | ||
| 966 | + | ||
| 967 | + // Log photon rate | ||
| 968 | + if (logNormal()) { | ||
| 969 | + *wrklog << gammalib::parformat("Photon rate", indent); | ||
| 970 | + *wrklog << rate << " photons/s"; | ||
| 971 | + if (model->name().length() > 0) { | ||
| 972 | + *wrklog << " [" << model->name() << "]"; | ||
| 973 | + } | ||
| 974 | + *wrklog << std::endl; | ||
| 975 | + } | ||
| 976 | + | ||
| 977 | + // If photon rate exceeds the maximum photon rate that is allowed | ||
| 978 | + // then throw an exception | ||
| 979 | + if (rate > m_max_rate) { | ||
| 980 | + std::string mod = (model->name().length() > 0) ? | ||
| 981 | + model->name() : "Unknown"; | ||
| 982 | + std::string msg = "Photon rate "+gammalib::str(rate)+ | ||
| 983 | + " photons/s for model \""+mod+"\" exceeds " | ||
| 984 | + "maximum allowed photon rate of "+ | ||
| 985 | + gammalib::str(m_max_rate)+" photons/s. " | ||
| 986 | + "Please check the model parameters for " | ||
| 987 | + "model \""+mod+"\" or increase the value " | ||
| 988 | + "of the \"maxrate\" parameter."; | ||
| 989 | + throw GException::invalid_value(G_SIMULATE_INTERVAL, msg); | ||
| 990 | + } | ||
| 991 | + | ||
| 992 | + // To reduce memory requirements we split long time intervals into | ||
| 993 | + // several time slices | ||
| 994 | + GTime tstart = tmin; | ||
| 995 | + GTime tstop = tstart + tslice; | ||
| 996 | + | ||
| 997 | + // Save state of photon and event counters before doing the | ||
| 998 | + // simulation | ||
| 999 | + int nphotons_before = nphotons[i]; | ||
| 1000 | + int nevents_before = nevents[i]; | ||
| 1001 | + | ||
| 1002 | + // Loop over time slices | ||
| 1003 | + while (tstart < tmax) { | ||
| 1004 | + | ||
| 1005 | + // Make sure that tstop <= tmax | ||
| 1006 | + if (tstop > tmax) { | ||
| 1007 | + tstop = tmax; | ||
| 1008 | + } | ||
| 1009 | + | ||
| 1010 | + // Log time slice | ||
| 1011 | + if (logExplicit()) { | ||
| 1012 | + if (tmax - tmin > tslice) { | ||
| 1013 | + indent++; | ||
| 1014 | + wrklog->indent(indent); | ||
| 1015 | + } | ||
| 1016 | + *wrklog << gammalib::parformat("Time slice", indent); | ||
| 1017 | + *wrklog << tstart.convert(m_cta_ref) << " - "; | ||
| 1018 | + *wrklog << tstop.convert(m_cta_ref) << " s"; | ||
| 1019 | + if (model->name().length() > 0) { | ||
| 1020 | + *wrklog << " [" << model->name() << "]"; | ||
| 1021 | + } | ||
| 1022 | + *wrklog << std::endl; | ||
| 1023 | + } | ||
| 1024 | + | ||
| 1025 | + // Simulate time slice | ||
| 1026 | + simulate_time_slice(obs, rsp, events, model, tstart, tstop, | ||
| 1027 | + emin, emax, dir, rad, area, | ||
| 1028 | + ran, wrklog, indent, | ||
| 1029 | + nphotons[i], nevents[i]); | ||
| 1030 | + | ||
| 1031 | + // Go to next time slice | ||
| 1032 | + tstart = tstop; | ||
| 1033 | + tstop = tstart + tslice; | ||
| 1034 | + | ||
| 1035 | + // Reset indentation | ||
| 1036 | + if (logExplicit()) { | ||
| 1037 | + if (tmax - tmin > tslice) { | ||
| 1038 | + indent--; | ||
| 1039 | + wrklog->indent(indent); | ||
| 1040 | + } | ||
| 1041 | + } | ||
| 1042 | + | ||
| 1043 | + } // endwhile: looped over time slices | ||
| 1044 | + | ||
| 1045 | + // Log simulation results | ||
| 1046 | + if (logNormal()) { | ||
| 1047 | + *wrklog << gammalib::parformat("MC source photons", indent); | ||
| 1048 | + *wrklog << nphotons[i] - nphotons_before; | ||
| 1049 | + if (model->name().length() > 0) { | ||
| 1050 | + *wrklog << " [" << model->name() << "]"; | ||
| 1051 | + } | ||
| 1052 | + *wrklog << std::endl; | ||
| 1053 | + *wrklog << gammalib::parformat("MC source events", indent); | ||
| 1054 | + *wrklog << nevents[i] - nevents_before; | ||
| 1055 | + if (model->name().length() > 0) { | ||
| 1056 | + *wrklog << " [" << model->name() << "]"; | ||
| 1057 | + } | ||
| 1058 | + *wrklog << std::endl; | ||
| 1059 | + | ||
| 1060 | + } | ||
| 1061 | + | ||
| 1062 | + } // endfor: looped over models | ||
| 1063 | + | ||
| 1064 | + // Return | ||
| 1065 | + return; | ||
| 1066 | +} | ||
| 1067 | + | ||
| 1068 | + | ||
| 1069 | +/***********************************************************************//** | ||
| 1070 | + * @brief Simulate source events for a time slice | ||
| 1071 | + * | ||
| 1072 | + * @param[in] obs Pointer on CTA observation. | ||
| 1073 | + * @param[in,out] events Pointer on CTA event list. | ||
| 1074 | + * @param[in] models Model list. | ||
| 1075 | + * @param[in] tmin Start time. | ||
| 1076 | + * @param[in] tmax Stop time. | ||
| 1077 | + * @param[in] emin Minimum energy. | ||
| 1078 | + * @param[in] emax Maximum energy. | ||
| 1079 | + * @param[in] dir Simulation cone centre. | ||
| 1080 | + * @param[in] rad Simulation cone radius (degrees). | ||
| 1081 | + * @param[in] area Simulation area (cm^2). | ||
| 1082 | + * @param[in,out] ran Random number generator. | ||
| 1083 | + * @param[in] wrklog Pointer to logger. | ||
| 1084 | + * @param[in,out] indent Logger indent. | ||
| 1085 | + * @param[in,out] nphotons Number of photons. | ||
| 1086 | + * @param[in,out] nevents Number of events. | ||
| 1087 | + * | ||
| 1088 | + * Simulate source events for a time slice. | ||
| 1089 | + ***************************************************************************/ | ||
| 1090 | +void ctobssim::simulate_time_slice(GCTAObservation* obs, | ||
| 1091 | + const GCTAResponseIrf* rsp, | ||
| 1092 | + GCTAEventList* events, | ||
| 1093 | + const GModelSky* model, | ||
| 1094 | + const GTime& tstart, | ||
| 1095 | + const GTime& tstop, | ||
| 1096 | + const GEnergy& emin, | ||
| 1097 | + const GEnergy& emax, | ||
| 1098 | + const GSkyDir& dir, | ||
| 1099 | + const double& rad, | ||
| 1100 | + const double& area, | ||
| 1101 | + GRan& ran, | ||
| 1102 | + GLog* wrklog, | ||
| 1103 | + int& indent, | ||
| 1104 | + int& nphotons, | ||
| 1105 | + int& nevents) | ||
| 1106 | +{ | ||
| 1107 | + // Get photons | ||
| 1108 | + GPhotons photons = model->mc(area, dir, rad, emin, emax, tstart, tstop, | ||
| 1109 | + ran); | ||
| 1110 | + | ||
| 1111 | + // Dump number of simulated photons | ||
| 1112 | + if (logExplicit()) { | ||
| 1113 | + *wrklog << gammalib::parformat("MC source photons/slice", indent); | ||
| 1114 | + *wrklog << photons.size(); | ||
| 1115 | + if (model->name().length() > 0) { | ||
| 1116 | + *wrklog << " [" << model->name() << "]"; | ||
| 1117 | + } | ||
| 1118 | + *wrklog << std::endl; | ||
| 1119 | + } | ||
| 1120 | + | ||
| 1121 | + // Simulate events from photons | ||
| 1122 | + for (int i = 0; i < photons.size(); ++i) { | ||
| 1123 | + | ||
| 1124 | + // Increment photon counter | ||
| 1125 | + nphotons++; | ||
| 1126 | + | ||
| 1127 | + // Simulate event. Note that this method includes the deadtime | ||
| 1128 | + // correction. | ||
| 1129 | + GCTAEventAtom* event = rsp->mc(area, photons[i], *obs, ran); | ||
| 1130 | + | ||
| 1131 | + // Use event only if it exists and if it falls within ROI, the | ||
| 1132 | + // energy interval and the time slice | ||
| 1133 | + if (event != NULL) { | ||
| 1134 | + if (events->roi().contains(*event) && | ||
| 1135 | + event->energy() >= emin && | ||
| 1136 | + event->energy() <= emax && | ||
| 1137 | + event->time() >= tstart && | ||
| 1138 | + event->time() <= tstop) { | ||
| 1139 | + event->event_id(m_event_id); | ||
| 1140 | + events->append(*event); | ||
| 1141 | + m_event_id++; | ||
| 1142 | + nevents++; | ||
| 1143 | + } | ||
| 1144 | + delete event; | ||
| 1145 | + } | ||
| 1146 | + | ||
| 1147 | + } // endfor: looped over events | ||
| 1148 | + | ||
| 1149 | + // Return | ||
| 1150 | + return; | ||
| 1151 | +} | ||
| 1152 | + | ||
| 1153 | + | ||
| 1154 | +/***********************************************************************//** | ||
| 1155 | + * @brief Get energy boundaries | ||
| 1156 | + * | ||
| 1157 | + * @param[in] ebounds Energy boundaries of events. | ||
| 1158 | + * @return Energy boundaries for simulation. | ||
| 1159 | + * | ||
| 1160 | + * Get the energy boundaries for the source simulation. | ||
| 1161 | + * | ||
| 1162 | + * @todo Need to take care of the (rare) case that there are distinct | ||
| 1163 | + * energy boundaries in the event list. In that case we need to | ||
| 1164 | + * create mixed energy boundaries. | ||
| 1165 | + ***************************************************************************/ | ||
| 1166 | +GEbounds ctobssim::get_ebounds(const GEbounds& ebounds) const | ||
| 1167 | +{ | ||
| 1168 | + // Set energy bins | ||
| 1169 | + GEbounds ebins(m_eslices, ebounds.emin(), ebounds.emax()); | ||
| 1170 | + | ||
| 1171 | + // Return energy bins | ||
| 1172 | + return (ebins); | ||
| 1173 | +} | ||
| 1174 | + | ||
| 1175 | + | ||
| 1176 | +/***********************************************************************//** | ||
| 1177 | + * @brief Get simulation area (cm^2) | ||
| 1178 | + * | ||
| 1179 | + * @param[in] obs Pointer on CTA observation. | ||
| 1180 | + * @param[in] emin Minimum energy. | ||
| 1181 | + * @param[in] emax Maximum energy. | ||
| 1182 | + * @return Simulation area (cm^2). | ||
| 1183 | + * | ||
| 1184 | + * Get the simulation area for an energy interval in units of cm^2. | ||
| 1185 | + ***************************************************************************/ | ||
| 1186 | +double ctobssim::get_area(GCTAObservation* obs, | ||
| 1187 | + const GEnergy& emin, | ||
| 1188 | + const GEnergy& emax) const | ||
| 1189 | +{ | ||
| 1190 | + // Get CTA response | ||
| 1191 | + const GCTAResponseIrf* rsp = | ||
| 1192 | + dynamic_cast<const GCTAResponseIrf*>(obs->response()); | ||
| 1193 | + if (rsp == NULL) { | ||
| 1194 | + std::string cls = std::string(typeid(rsp).name()); | ||
| 1195 | + std::string msg = "Response of type \""+cls+"\" is not a CTA IRF " | ||
| 1196 | + "response. Please make sure that a CTA IRF " | ||
| 1197 | + "response is contained in the CTA observation."; | ||
| 1198 | + throw GException::invalid_value(G_GET_AREA, msg); | ||
| 1199 | + } | ||
| 1200 | + | ||
| 1201 | + // Compute effective area at minimum and maximum energy | ||
| 1202 | + double area_emin = rsp->aeff()->max(emin.log10TeV(), 0.0, 0.0); | ||
| 1203 | + double area_emax = rsp->aeff()->max(emax.log10TeV(), 0.0, 0.0); | ||
| 1204 | + | ||
| 1205 | + // Use maximum of both | ||
| 1206 | + double area = (area_emin > area_emax) ? area_emin : area_emax; | ||
| 1207 | + | ||
| 1208 | + // Multiply by security factor | ||
| 1209 | + area *= 2.0; | ||
| 1210 | + | ||
| 1211 | + // Return simulation area | ||
| 1212 | + return area; | ||
| 1213 | +} | ||
| 1214 | + | ||
| 1215 | + | ||
| 1216 | +/***********************************************************************//** | ||
| 995 | * @brief Determine sky model flux | 1217 | * @brief Determine sky model flux |
| 996 | * | 1218 | * |
| 997 | * @param[in] model Sky model. | 1219 | * @param[in] model Sky model. |
| @@ -1000,7 +1222,7 @@ void ctobssim::simulate_source(GCTAObservation* obs, const GModels& models, | @@ -1000,7 +1222,7 @@ void ctobssim::simulate_source(GCTAObservation* obs, const GModels& models, | ||
| 1000 | * @param[in] centre Centre of region for photon rate determination. | 1222 | * @param[in] centre Centre of region for photon rate determination. |
| 1001 | * @param[in] radius Radius of region for photon rate determination (degrees). | 1223 | * @param[in] radius Radius of region for photon rate determination (degrees). |
| 1002 | * @param[in] indent Indent for logging. | 1224 | * @param[in] indent Indent for logging. |
| 1003 | - * @param[in,out] wrklog Pointer to logger (default: NULL). | 1225 | + * @param[in,out] wrklog Pointer to logger. |
| 1004 | * @return Model flux (photons/cm2/sec). | 1226 | * @return Model flux (photons/cm2/sec). |
| 1005 | ***************************************************************************/ | 1227 | ***************************************************************************/ |
| 1006 | double ctobssim::get_model_flux(const GModelSky* model, | 1228 | double ctobssim::get_model_flux(const GModelSky* model, |
src/ctobssim/ctobssim.hpp
| 1 | /*************************************************************************** | 1 | /*************************************************************************** |
| 2 | * ctobssim - Observation simulator tool * | 2 | * ctobssim - Observation simulator tool * |
| 3 | * ----------------------------------------------------------------------- * | 3 | * ----------------------------------------------------------------------- * |
| 4 | - * copyright (C) 2011-2015 by Juergen Knoedlseder * | 4 | + * copyright (C) 2011-2016 by Juergen Knoedlseder * |
| 5 | * ----------------------------------------------------------------------- * | 5 | * ----------------------------------------------------------------------- * |
| 6 | * * | 6 | * * |
| 7 | * This program is free software: you can redistribute it and/or modify * | 7 | * This program is free software: you can redistribute it and/or modify * |
| @@ -34,7 +34,7 @@ | @@ -34,7 +34,7 @@ | ||
| 34 | 34 | ||
| 35 | /* __Definitions _________________________________________________________ */ | 35 | /* __Definitions _________________________________________________________ */ |
| 36 | #define CTOBSSIM_NAME "ctobssim" | 36 | #define CTOBSSIM_NAME "ctobssim" |
| 37 | -#define CTOBSSIM_VERSION "1.0.0" | 37 | +#define CTOBSSIM_VERSION "1.1.0" |
| 38 | 38 | ||
| 39 | 39 | ||
| 40 | /***********************************************************************//** | 40 | /***********************************************************************//** |
| @@ -71,38 +71,74 @@ public: | @@ -71,38 +71,74 @@ public: | ||
| 71 | 71 | ||
| 72 | protected: | 72 | protected: |
| 73 | // Protected methods | 73 | // Protected methods |
| 74 | - void init_members(void); | ||
| 75 | - void copy_members(const ctobssim& app); | ||
| 76 | - void free_members(void); | ||
| 77 | - void get_parameters(void); | ||
| 78 | - void simulate_source(GCTAObservation* obs, | ||
| 79 | - const GModels& models, | ||
| 80 | - GRan& ran, | ||
| 81 | - GLog* wrklog = NULL); | ||
| 82 | - double get_model_flux(const GModelSky* model, | ||
| 83 | - const GEnergy& emin, | ||
| 84 | - const GEnergy& emax, | ||
| 85 | - const GSkyDir& centre, | ||
| 86 | - const double& radius, | ||
| 87 | - const int& indent, | ||
| 88 | - GLog* wrklog = NULL); | ||
| 89 | - void simulate_background(GCTAObservation* obs, | ||
| 90 | - const GModels& models, | ||
| 91 | - GRan& ran, | ||
| 92 | - GLog* wrklog = NULL); | ||
| 93 | - void save_fits(void); | ||
| 94 | - void save_xml(void); | 74 | + void init_members(void); |
| 75 | + void copy_members(const ctobssim& app); | ||
| 76 | + void free_members(void); | ||
| 77 | + void get_parameters(void); | ||
| 78 | + void simulate_source(GCTAObservation* obs, | ||
| 79 | + const GModels& models, | ||
| 80 | + GRan& ran, | ||
| 81 | + GLog* wrklog = NULL); | ||
| 82 | + void simulate_interval(GCTAObservation* obs, | ||
| 83 | + const GCTAResponseIrf* rsp, | ||
| 84 | + GCTAEventList* events, | ||
| 85 | + const GModels& models, | ||
| 86 | + const GTime& tmin, | ||
| 87 | + const GTime& tmax, | ||
| 88 | + const GEnergy& emin, | ||
| 89 | + const GEnergy& emax, | ||
| 90 | + const GSkyDir& dir, | ||
| 91 | + const double& rad, | ||
| 92 | + const double& area, | ||
| 93 | + GRan& ran, | ||
| 94 | + GLog* wrklog, | ||
| 95 | + int& indent, | ||
| 96 | + std::vector<int>& nphotons, | ||
| 97 | + std::vector<int>& nevents); | ||
| 98 | + void simulate_time_slice(GCTAObservation* obs, | ||
| 99 | + const GCTAResponseIrf* rsp, | ||
| 100 | + GCTAEventList* events, | ||
| 101 | + const GModelSky* model, | ||
| 102 | + const GTime& tstart, | ||
| 103 | + const GTime& tstop, | ||
| 104 | + const GEnergy& emin, | ||
| 105 | + const GEnergy& emax, | ||
| 106 | + const GSkyDir& dir, | ||
| 107 | + const double& rad, | ||
| 108 | + const double& area, | ||
| 109 | + GRan& ran, | ||
| 110 | + GLog* wrklog, | ||
| 111 | + int& indent, | ||
| 112 | + int& nphotons, | ||
| 113 | + int& nevents); | ||
| 114 | + GEbounds get_ebounds(const GEbounds& ebounds) const; | ||
| 115 | + double get_area(GCTAObservation* obs, | ||
| 116 | + const GEnergy& emin, | ||
| 117 | + const GEnergy& emax) const; | ||
| 118 | + double get_model_flux(const GModelSky* model, | ||
| 119 | + const GEnergy& emin, | ||
| 120 | + const GEnergy& emax, | ||
| 121 | + const GSkyDir& centre, | ||
| 122 | + const double& radius, | ||
| 123 | + const int& indent, | ||
| 124 | + GLog* wrklog); | ||
| 125 | + void simulate_background(GCTAObservation* obs, | ||
| 126 | + const GModels& models, | ||
| 127 | + GRan& ran, | ||
| 128 | + GLog* wrklog = NULL); | ||
| 129 | + void save_fits(void); | ||
| 130 | + void save_xml(void); | ||
| 95 | 131 | ||
| 96 | // User parameters | 132 | // User parameters |
| 97 | std::string m_outevents; //!< Output events file | 133 | std::string m_outevents; //!< Output events file |
| 98 | std::string m_prefix; //!< Prefix for multiple event lists | 134 | std::string m_prefix; //!< Prefix for multiple event lists |
| 99 | int m_seed; //!< Random number generator seed | 135 | int m_seed; //!< Random number generator seed |
| 136 | + int m_eslices; //!< Number of energy slices | ||
| 100 | bool m_apply_edisp; //!< Apply energy dispersion? | 137 | bool m_apply_edisp; //!< Apply energy dispersion? |
| 101 | 138 | ||
| 102 | // Protected members | 139 | // Protected members |
| 103 | mutable GObservations m_obs; //!< Observation container | 140 | mutable GObservations m_obs; //!< Observation container |
| 104 | mutable bool m_save_and_dispose; //!< Save and dispose immediately | 141 | mutable bool m_save_and_dispose; //!< Save and dispose immediately |
| 105 | - double m_area; //!< Surface area for simulation (cm2) | ||
| 106 | int m_max_photons; //!< Maximum number of photons/slice | 142 | int m_max_photons; //!< Maximum number of photons/slice |
| 107 | double m_max_rate; //!< Maximum photon rate | 143 | double m_max_rate; //!< Maximum photon rate |
| 108 | std::vector<GRan> m_rans; //!< Random number generators | 144 | std::vector<GRan> m_rans; //!< Random number generators |
src/ctobssim/ctobssim.par
| @@ -5,7 +5,7 @@ | @@ -5,7 +5,7 @@ | ||
| 5 | # ------------------------------------------------------------------------- # | 5 | # ------------------------------------------------------------------------- # |
| 6 | # # | 6 | # # |
| 7 | # File: ctobssim.par # | 7 | # File: ctobssim.par # |
| 8 | -# Version: 1.0.0 # | 8 | +# Version: 1.1.0 # |
| 9 | # # | 9 | # # |
| 10 | # Author: Jurgen Knodlseder # | 10 | # Author: Jurgen Knodlseder # |
| 11 | # Jurgen.Knodlseder@irap.omp.eu # | 11 | # Jurgen.Knodlseder@irap.omp.eu # |
| @@ -38,6 +38,7 @@ emin, r, a, 0.1,,, "Lower energy limit (TeV)" | @@ -38,6 +38,7 @@ emin, r, a, 0.1,,, "Lower energy limit (TeV)" | ||
| 38 | emax, r, a, 100.0,,, "Upper energy limit (TeV)" | 38 | emax, r, a, 100.0,,, "Upper energy limit (TeV)" |
| 39 | deadc, r, h, 0.95,0,1, "Average deadtime correction factor" | 39 | deadc, r, h, 0.95,0,1, "Average deadtime correction factor" |
| 40 | maxrate, r, h, 1.0e6,,, "Maximum photon rate" | 40 | maxrate, r, h, 1.0e6,,, "Maximum photon rate" |
| 41 | +eslices, i, h, 10,1,100,"Number of energy slices" | ||
| 41 | 42 | ||
| 42 | # | 43 | # |
| 43 | # Standard parameters | 44 | # Standard parameters |