ctools 2.1.0.dev
Loading...
Searching...
No Matches
ctbutterfly.cpp
Go to the documentation of this file.
1/***************************************************************************
2 * ctbutterfly - butterfly calculation tool *
3 * ----------------------------------------------------------------------- *
4 * copyright (C) 2014-2022 by Michael Mayer *
5 * ----------------------------------------------------------------------- *
6 * *
7 * This program is free software: you can redistribute it and/or modify *
8 * it under the terms of the GNU General Public License as published by *
9 * the Free Software Foundation, either version 3 of the License, or *
10 * (at your option) any later version. *
11 * *
12 * This program is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 * GNU General Public License for more details. *
16 * *
17 * You should have received a copy of the GNU General Public License *
18 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
19 * *
20 ***************************************************************************/
21/**
22 * @file ctbutterfly.cpp
23 * @brief Butterfly computation tool
24 * @author Michael Mayer
25 */
26
27/* __ Includes ___________________________________________________________ */
28#ifdef HAVE_CONFIG_H
29#include <config.h>
30#endif
31#include <cstdio>
32#include <fstream>
33#include "ctbutterfly.hpp"
34#include "GTools.hpp"
35
36/* __ Method name definitions ____________________________________________ */
37#define G_GET_PARAMETERS "ctbutterfly::get_parameters()"
38#define G_SAVE "ctbutterfly::save()"
39#define G_CHECK_MODEL "ctbutterfly::check_model()"
40
41/* __ Debug definitions __________________________________________________ */
42
43/* __ Coding definitions _________________________________________________ */
44
45
46/*==========================================================================
47 = =
48 = Constructors/destructors =
49 = =
50 ==========================================================================*/
51
52/***********************************************************************//**
53 * @brief Void constructor
54 ***************************************************************************/
56{
57 // Initialise members
59
60 // Return
61 return;
62}
63
64
65/***********************************************************************//**
66 * @brief Observations constructor
67 *
68 * param[in] obs Observation container.
69 *
70 * This method creates an instance of the class by copying an existing
71 * observations container.
72 ***************************************************************************/
73ctbutterfly::ctbutterfly(const GObservations& obs) :
74 ctlikelihood(CTBUTTERFLY_NAME, VERSION, obs)
75{
76 // Initialise members
78
79 // Return
80 return;
81}
82
83
84
85/***********************************************************************//**
86 * @brief Command line constructor
87 *
88 * @param[in] argc Number of arguments in command line.
89 * @param[in] argv Array of command line arguments.
90 ***************************************************************************/
91ctbutterfly::ctbutterfly(int argc, char *argv[]) :
92 ctlikelihood(CTBUTTERFLY_NAME, VERSION, argc, argv)
93{
94 // Initialise members
96
97 // Return
98 return;
99}
100
101
102/***********************************************************************//**
103 * @brief Copy constructor
104 *
105 * @param[in] app Application.
106 ***************************************************************************/
108{
109 // Initialise members
110 init_members();
111
112 // Copy members
113 copy_members(app);
114
115 // Return
116 return;
117}
118
119
120/***********************************************************************//**
121 * @brief Destructor
122 ***************************************************************************/
124{
125 // Free members
126 free_members();
127
128 // Return
129 return;
130}
131
132
133/*==========================================================================
134 = =
135 = Operators =
136 = =
137 ==========================================================================*/
138
139/***********************************************************************//**
140 * @brief Assignment operator
141 *
142 * @param[in] app Application.
143 * @return Application.
144 ***************************************************************************/
146{
147 // Execute only if object is not identical
148 if (this != &app) {
149
150 // Copy base class members
151 this->ctlikelihood::operator=(app);
152
153 // Free members
154 free_members();
155
156 // Initialise members
157 init_members();
158
159 // Copy members
160 copy_members(app);
161
162 } // endif: object was not identical
163
164 // Return this object
165 return *this;
166}
167
168
169/*==========================================================================
170 = =
171 = Public methods =
172 = =
173 ==========================================================================*/
174
175/***********************************************************************//**
176 * @brief Clear ctbutterfly tool
177 *
178 * Clears ctbutterfly tool.
179 ***************************************************************************/
181{
182 // Free members
183 free_members();
186 this->ctool::free_members();
187
188 // Clear base class (needed to conserve tool name and version)
189 this->GApplication::clear();
190
191 // Initialise members
192 this->ctool::init_members();
195 init_members();
196
197 // Write header into logger
198 log_header();
199
200 // Return
201 return;
202}
203
204
205/***********************************************************************//**
206 * @brief Computes the butterfly
207 *
208 * This method takes the spectral fit and its covariance matrix to compute
209 * the confidence band via Gaussian error propagation
210 ***************************************************************************/
212{
213 // Get task parameters
215
216 // Set energy dispersion flag for all CTA observations and save old
217 // values in save_edisp vector
218 std::vector<bool> save_edisp;
219 save_edisp.assign(m_obs.size(), false);
220 for (int i = 0; i < m_obs.size(); ++i) {
221 GCTAObservation* obs = dynamic_cast<GCTAObservation*>(m_obs[i]);
222 if (obs != NULL) {
223 save_edisp[i] = obs->response()->apply_edisp();
224 obs->response()->apply_edisp(m_apply_edisp);
225 }
226 }
227
228 // Write input observation container into logger
229 log_observations(NORMAL, m_obs, "Input observation");
230
231 // If fit is selected then do maximum likelihood fit
232 if (m_fit) {
233
234 // Write header into logger
235 log_header1(TERSE, "Compute best-fit likelihood");
236
237 // Optimize and compute errors
238 m_obs.optimize(m_opt);
239 m_obs.errors(m_opt);
240
241 // Get covariance matrix. For the envelope method we need an unscaled
242 // matrix, hence we directly access the curvature matrix and invert
243 // it
244 GObservations::likelihood likelihood = m_obs.function();
245 if (m_method == "GAUSSIAN") {
246 m_covariance = likelihood.covariance();
247 }
248 else {
249 m_covariance = likelihood.curvature()->invert();
250 }
251
252 // Write optimizer, optimised model and covariance matrix into logger
253 log_string(NORMAL, m_opt.print(m_chatter));
254 log_string(NORMAL, m_obs.models().print(m_chatter));
255 log_string(EXPLICIT, m_covariance.print(m_chatter));
256
257 } // endif: fit selected
258
259 // Get model instance for further computations
260 GModels models = m_obs.models();
261
262 // If no fit is selected and no covariance matrix has been specified
263 // then compute now the covariance matrix
264 if (!m_fit && m_covariance.size() == 0) {
265
266 // Write header into logger
267 log_header1(TERSE, "Compute covariance matrix");
268
269 // Evaluate curvature matrix at the actual parameters
270 GOptimizerPars pars = models.pars();
271 GObservations::likelihood likelihood = m_obs.function();
272 likelihood.eval(pars);
273
274 // Get covariance matrix. For the envelope method we need an unscaled
275 // matrix, hence we directly access the curvature matrix and invert
276 // it
277 if (m_method == "GAUSSIAN") {
278 m_covariance = likelihood.covariance();
279 }
280 else {
281 m_covariance = likelihood.curvature()->invert();
282 }
283
284 // Write covariance matrix into logger
285 log_string(EXPLICIT, m_covariance.print(m_chatter));
286
287 } // endif: covariance computation needed
288
289 // Compute butterfly depending on selected method
290 if (m_method == "GAUSSIAN") {
292 }
293 else {
294 ellipsoid_boundary(models);
295 }
296
297 // Create FITS table
298 create_fits();
299
300 // Write header into logger
301 log_header1(TERSE, "Results");
302
303 // Show results by converting from MeV to TeV
304 for (int k = 0; k < m_ebounds.size(); ++k) {
305
306 // Write message
307 std::string key = "Intensity at " +
308 gammalib::str(m_energies[k]*1.0e-6) +
309 " TeV";
310 std::string value = gammalib::str(m_intensities[k]*1.0e6) + " (" +
311 gammalib::str(m_min_intensities[k]*1.0e6) + ", " +
312 gammalib::str(m_max_intensities[k]*1.0e6) +
313 ") ph/cm2/s/TeV";
314
315 // Write results into logger
316 log_value(NORMAL, key, value);
317
318 } // endfor: loop over energy bin
319
320 // Restore energy dispersion flag for all CTA observations
321 for (int i = 0; i < m_obs.size(); ++i) {
322 GCTAObservation* obs = dynamic_cast<GCTAObservation*>(m_obs[i]);
323 if (obs != NULL) {
324 obs->response()->apply_edisp(save_edisp[i]);
325 }
326 }
327
328 // Return
329 return;
330}
331
332
333/***********************************************************************//**
334 * @brief Save butterfly diagram
335 *
336 * Saves the butterfly diagram FITS file.
337 ***************************************************************************/
339{
340 // Write header into logger
341 log_header1(TERSE, "Save Butterfly diagram");
342
343 // Save only if filename is valid
344 if ((*this)["outfile"].is_valid()) {
345
346 // Get output filename
347 m_outfile = (*this)["outfile"].filename();
348
349 // Log butterfly diagram file name
350 log_value(NORMAL, "Butterfly file", m_outfile.url());
351
352 // Save FITS table
353 m_fits.saveto(m_outfile.url(), clobber());
354
355 }
356
357 // Return
358 return;
359}
360
361
362/*==========================================================================
363 = =
364 = Private methods =
365 = =
366 ==========================================================================*/
367
368/***********************************************************************//**
369 * @brief Initialise class members
370 ***************************************************************************/
372{
373 // Initialise members
374 m_srcname.clear();
375 m_method.clear();
376 m_confidence = 0.68;
377 m_apply_edisp = false;
378 m_fit = false;
379 m_chatter = static_cast<GChatter>(2);
380 m_ebounds.clear();
381 m_outfile.clear();
382
383 // Initialise protected members
384 m_covariance.clear();
385 m_energies.clear();
386 m_intensities.clear();
387 m_min_intensities.clear();
388 m_max_intensities.clear();
389 m_fits.clear();
390
391 // Return
392 return;
393}
394
395
396/***********************************************************************//**
397 * @brief Copy class members
398 *
399 * @param[in] app Application.
400 ***************************************************************************/
402{
403 // Copy attributes
404 m_srcname = app.m_srcname;
405 m_method = app.m_method;
406 m_confidence = app.m_confidence;
407 m_max_iter = app.m_max_iter;
408 m_apply_edisp = app.m_apply_edisp;
409 m_fit = app.m_fit;
410 m_chatter = app.m_chatter;
411 m_ebounds = app.m_ebounds;
412 m_outfile = app.m_outfile;
413
414 // Copy protected members
415 m_covariance = app.m_covariance;
416 m_energies = app.m_energies;
417 m_intensities = app.m_intensities;
418 m_min_intensities = app.m_min_intensities;
419 m_max_intensities = app.m_max_intensities;
420 m_fits = app.m_fits;
421
422 // Return
423 return;
424}
425
426
427/***********************************************************************//**
428 * @brief Delete class members
429 ***************************************************************************/
431{
432 // Return
433 return;
434}
435
436
437/***********************************************************************//**
438 * @brief Get application parameters
439 *
440 * @exception GException::feature_not_implemented
441 * Loading of covariance matrix is not yet implemented.
442 *
443 * Get all task parameters from parameter file.
444 ***************************************************************************/
446{
447 // Setup observations from "inobs" parameter
449
450 // Set observation statistic
451 set_obs_statistic(gammalib::toupper((*this)["statistic"].string()));
452
453 // Setup models from "inmodel" parameter
454 setup_models(m_obs, (*this)["srcname"].string());
455
456 // Get name of test source
457 m_srcname = (*this)["srcname"].string();
458
459 // Create energy boundaries from user parameters
461
462 // Get matrix file name and load if possible
463 if ((*this)["matrix"].is_valid()) {
464 std::string msg = "Loading of matrix from file not implemented yet. "
465 "Use filename = \"NONE\" to induce a recomputation "
466 "of the matrix internally.";
467 throw GException::feature_not_implemented(G_GET_PARAMETERS, msg);
468 // m_covariance.load(matrixfilename);
469 }
470
471 // Set optimizer characteristics from user parameters
472 m_opt.eps((*this)["like_accuracy"].real());
473 m_opt.max_iter((*this)["max_iter"].integer());
474
475 // Get remaining parameters
476 m_apply_edisp = (*this)["edisp"].boolean();
477 m_method = (*this)["method"].string();
478 m_confidence = (*this)["confidence"].real();
479 m_fit = (*this)["fit"].boolean();
480 m_chatter = static_cast<GChatter>((*this)["chatter"].integer());
481
482 // Check model name and type
483 check_model();
484
485 // If needed later, query output filename now
486 if (read_ahead()) {
487 (*this)["outfile"].query();
488 }
489
490 // Write parameters into logger
491 log_parameters(TERSE);
492
493 // Return
494 return;
495}
496
497
498/***********************************************************************//**
499 * @brief Compute butterfly using the ellipsoid boundary method
500 *
501 * @param[in] models Models.
502 ***************************************************************************/
504{
505 // Write header into logger
506 log_header1(TERSE, "Prepare butterfly computation");
507
508 // Find parameter indices. We do this by the memory location of the
509 // model parameters.
510 GModelSky* skymodel = dynamic_cast<GModelSky*>(models[m_srcname]);
511 GModelPar* par_prefactor = &(*skymodel)["Prefactor"];
512 GModelPar* par_index = &(*skymodel)["Index"];
513 int inx_prefactor = -1;
514 int inx_index = -1;
515 for (int i = 0; i < models.npars(); ++i) {
516 if (models.pars()[i] == par_prefactor) {
517 inx_prefactor = i;
518 }
519 if (models.pars()[i] == par_index) {
520 inx_index = i;
521 }
522 }
523
524 // Store model values
525 double prefactor_mean = (*skymodel)["Prefactor"].value();
526 double index_mean = (*skymodel)["Index"].value();
527 double pivot_mean = (*skymodel)["PivotEnergy"].value();
528 double prefactor_scale = (*skymodel)["Prefactor"].scale();
529 double index_scale = (*skymodel)["Index"].scale();
530 GEnergy pivot(pivot_mean, "MeV");
531
532 // Write parameter indices into logger
533 log_value(NORMAL, "Prefactor", gammalib::str(prefactor_mean)+
534 " ph/cm2/s/MeV ("+
535 gammalib::str(inx_prefactor)+")");
536 log_value(NORMAL, "Index", gammalib::str(index_mean)+
537 " ("+gammalib::str(inx_index)+")");
538 log_value(NORMAL, "Pivot energy", pivot.print());
539
540 // Extract covariance elements
541 double cov_pp = m_covariance(inx_prefactor,inx_prefactor);
542 double cov_pg = m_covariance(inx_prefactor,inx_index);
543 double cov_gg = m_covariance(inx_index,inx_index);
544
545 // Compute eigenvectors and eigenvalues
546 double lambda1;
547 double lambda2;
548 GVector vector1(2);
549 GVector vector2(2);
550 eigenvectors(cov_pp, cov_pg, cov_pg, cov_gg,
551 &lambda1, &lambda2, &vector1, &vector2);
552
553 // Write eigenvectors and eigenvalues into logger
554 log_value(NORMAL, "Eigenvalue 1", lambda1);
555 log_value(NORMAL, "Eigenvalue 2", lambda2);
556 log_value(NORMAL, "Eigenvector 1", vector1.print());
557 log_value(NORMAL, "Eigenvector 2", vector2.print());
558
559 // Confidence scaling, calculated from a Chi-Squared distribution
560 // with 2 degrees of freedom
561 double scale = std::sqrt(-2.0 * std::log(1.0-m_confidence));
562
563 // Write confidence level information into logger
564 log_value(NORMAL, "Confidence level", m_confidence);
565 log_value(NORMAL, "Corresponding scaling", scale);
566
567 // Compute minor and major axes of error ellipse
568 double major = scale*std::sqrt(lambda1);
569 double minor = scale*std::sqrt(lambda2);
570
571 // Write header into logger
572 log_header1(TERSE, "Generate butterfly");
573
574 // Initialise result arrays
575 m_energies.assign(m_ebounds.size(), 0.0);
576 m_intensities.assign(m_ebounds.size(), 0.0);
577 m_min_intensities.assign(m_ebounds.size(), 1e30);
578 m_max_intensities.assign(m_ebounds.size(), 0.0);
579
580 // Walk around the error ellipse
581 int nt = 360;
582 double dt = gammalib::twopi/double(nt);
583 double t = 0.0;
584 for (int i = 0; i < nt; ++i, t += dt) {
585
586 // Pre-compute sin and cosine
587 double sin_t = std::sin(t);
588 double cos_t = std::cos(t);
589
590 // Compute prefactor and index
591 double prefactor = (major * cos_t * vector1[0] +
592 minor * sin_t * vector2[0]) * prefactor_scale +
593 prefactor_mean;
594 double index = (major * cos_t * vector1[1] +
595 minor * sin_t * vector2[1]) * index_scale +
596 index_mean;
597
598 // Write prefactor and index into logger
599 log_value(EXPLICIT, "Angle "+gammalib::str(t*gammalib::rad2deg),
600 gammalib::str(prefactor)+" ph/cm2/s/MeV; "+
601 gammalib::str(index));
602
603 // Setup power law model
604 GModelSpectralPlaw plaw(prefactor, index, pivot);
605
606 // Evaluate power law at each energy and extract minimum and
607 // maximum intensity
608 for (int k = 0; k < m_ebounds.size(); ++k) {
609
610 // Get the energy of current bin
611 GTime time;
612 GEnergy energy = m_ebounds.elogmean(k);
613
614 // Evaluate power law
615 double intensity = plaw.eval(energy, time);
616
617 // Get extremes
618 if (intensity < m_min_intensities[k]) {
619 m_min_intensities[k] = intensity;
620 }
621 if (intensity > m_max_intensities[k]) {
622 m_max_intensities[k] = intensity;
623 }
624
625 } // endfor: looped over all energies
626
627 } // endfor: looped over all angles
628
629 // Setup power law model for mean prefactor and index
630 GModelSpectralPlaw plaw(prefactor_mean, index_mean, pivot);
631
632 // Compute energy and intensity vectors for mean power law
633 for (int k = 0; k < m_ebounds.size(); ++k) {
634
635 // Get the energy of current bin
636 GTime time;
637 GEnergy energy = m_ebounds.elogmean(k);
638
639 // Evaluate power law
640 double intensity = plaw.eval(energy, time);
641
642 // Store results
643 m_energies[k] = energy.MeV();
644 m_intensities[k] = intensity;
645
646 } // endfor: looped over energies
647
648 // Return
649 return;
650}
651
652
653/***********************************************************************//**
654 * @brief Compute butterfly using Gaussian error propagation
655 *
656 * @param[in] models Models.
657 *
658 * Computes the butterfly diagram using Gaussian error propagation. This
659 * works for any kind of model.
660 ***************************************************************************/
662{
663 // Write header into logger
664 log_header1(TERSE, "Prepare butterfly computation");
665
666 // Confidence scaling
667 double scale = gammalib::erfinv(m_confidence) * gammalib::sqrt_two;
668
669 // Write confidence level information into logger
670 log_value(NORMAL, "Confidence level", m_confidence);
671 log_value(NORMAL, "Corresponding scaling", scale);
672
673 // Write header into logger
674 log_header1(TERSE, "Generate butterfly");
675
676 // Initialise result arrays
677 m_energies.clear();
678 m_intensities.clear();
679 m_min_intensities.clear();
680 m_max_intensities.clear();
681
682 // Initialise dummy time to evaluate spectral model
683 GTime time = GTime();
684
685 // Initialise vector of gradients
686 GVector grad = GVector(m_obs.models().npars());
687
688 // Loop over energy bins
689 for (int i = 0; i < m_ebounds.size(); ++i) {
690
691 // Initialise number of gradients
692 int num_gradient = 0;
693
694 // Get the mean logarithmic energy of current bin
695 GEnergy energy = m_ebounds.elogmean(i);
696
697 // Initialise model flux value
698 double model_flux = 0.0;
699
700 // Loop over models
701 for (int j = 0; j < models.size(); ++j) {
702
703 // Check wether model is a skymodel
704 GModelSky* skymodel = dynamic_cast<GModelSky*>(models[j]);
705
706 // Yes ...
707 if (skymodel != NULL) {
708
709 // Set flux value of source of interest, evaluate gradients
710 if (skymodel->name() == m_srcname) {
711
712 // Get spectral component of model
713 GModelSpectral *spectral = skymodel->spectral();
714
715 // Get model flux
716 model_flux = spectral->eval(energy, time, true);
717
718 // Loop over all model parameters
719 for (int k = 0; k < skymodel->size(); ++k) {
720
721 // Set gradient if we deal with spectral component.
722 // Remember that the gradient() method returns full
723 // parameter gradients (including the scale factor)
724 bool parIsSpectral = false;
725 for (int l = 0; l < spectral->size(); ++l) {
726 if ((&((*spectral)[l])) == (&((*skymodel)[k]))) {
727 grad[num_gradient] = (*spectral)[l].gradient();
728 num_gradient++;
729 parIsSpectral = true;
730 break;
731 }
732 } // endfor: looped over spectral parameters
733
734 // If parameter is spatial or temporal, count up
735 if (!parIsSpectral) {
736 num_gradient++;
737 }
738
739 } // endfor: looped over all model parameters
740
741 } // endif: model was source of interest
742 else {
743 num_gradient += skymodel->size();
744 }
745
746 } // endif: model was sky model
747
748 // Skip other models (e.g. GModelData instances)
749 else {
750 num_gradient += models[j]->size();
751 }
752
753 } // endfor: Looped over models
754
755 // Multiply covariance to the gradient vector
756 GVector vector = m_covariance * grad;
757
758 // Get the error from the scalar product. Make sure that square
759 // root does never get negative.
760 double arg = grad * vector;
761 double error = (arg > 0.0) ? std::sqrt(arg) : 0.0;
762
763 // Multiply with confidence scaling
764 error *= scale;
765
766 // Store flux, value and energy for saving
767 m_intensities.push_back(model_flux);
768 m_energies.push_back(energy.MeV());
769 m_min_intensities.push_back(model_flux-error);
770 m_max_intensities.push_back(model_flux+error);
771
772 } // endfor: Looped over energy bins
773
774 // Return
775 return;
776}
777
778
779/***********************************************************************//**
780 * @brief Check if sky model is valid
781 *
782 * @exception GException::invalid_value
783 * Did not find a valid model
784 *
785 * Checks whether the specified sky model exists and whether it is a power
786 * law.
787 ***************************************************************************/
789{
790 // Continue only if source model exists
791 if (m_obs.models().contains(m_srcname)) {
792
793 // Get relevant model and parameter for upper limit computation.
794 GModels& models = const_cast<GModels&>(m_obs.models());
795 GModelSky* model = dynamic_cast<GModelSky*>(models[m_srcname]);
796 if (model == NULL) {
797 std::string msg = "Source \""+m_srcname+"\" is not a sky model. "
798 "Please specify the name of a sky model for "
799 "butterfly computation.";
800 throw GException::invalid_value(G_CHECK_MODEL, msg);
801 }
802
803 // Check that the spectral model is a power law for the "ENVELOPE"
804 // method
805 if (m_method == "ENVELOPE") {
806 if (model->spectral()->type() != "PowerLaw") {
807 std::string msg = "\""+model->spectral()->type()+"\" cannot be "
808 "used as spectral model for an butterfly "
809 "computation with method=ENVELOPE. Please "
810 "specify a power law model or switch to "
811 "method=GAUSSIAN.";
812 throw GException::invalid_value(G_CHECK_MODEL, msg);
813 }
814 }
815
816 } // endif: source model existed
817
818 // Otherwise throw an exception
819 else {
820 std::string msg = "Source \""+m_srcname+"\" not found in model "
821 "container. Please add a source with that name "
822 "or check for possible typos.";
823 throw GException::invalid_value(G_CHECK_MODEL, msg);
824 }
825
826 // Return
827 return;
828}
829
830
831/***********************************************************************//**
832 * @brief Compute normalized eigenvectors and eigenvalues
833 *
834 * @param[in] a Covariance matrix element (0,0)
835 * @param[in] b Covariance matrix element (0,1)
836 * @param[in] c Covariance matrix element (1,0)
837 * @param[in] d Covariance matrix element (1,1)
838 * @param[out] lambda1 First eigenavlue
839 * @param[out] lambda2 Second eigenavlue
840 * @param[out] vector1 First eigenvector (normalized)
841 * @param[out] vector2 Second eigenvector (normalized)
842 *
843 * Computes the eigenvalues and eigenvectors for a 2x2 matrix. See
844 * http://www.math.harvard.edu/archive/21b_fall_04/exhibits/2dmatrices/index.html
845 ***************************************************************************/
846void ctbutterfly::eigenvectors(const double& a,
847 const double& b,
848 const double& c,
849 const double& d,
850 double* lambda1,
851 double* lambda2,
852 GVector* vector1,
853 GVector* vector2)
854{
855 // Compute trace and determinant
856 double trace = a + d;
857 double det = a*d - b*c;
858
859 // Compute eigenvalues
860 double arg1 = 0.5*trace;
861 double arg2 = std::sqrt(0.25*trace*trace - det);
862 *lambda1 = arg1 + arg2;
863 *lambda2 = arg1 - arg2;
864
865 // Compute eigenvectors
866 if (c != 0.0) {
867 (*vector1)[0] = *lambda1 - det;
868 (*vector1)[1] = c;
869 (*vector2)[0] = *lambda2 - det;
870 (*vector2)[1] = c;
871 }
872 else if (b != 0.0) {
873 (*vector1)[0] = b;
874 (*vector1)[1] = *lambda1 - a;
875 (*vector2)[0] = b;
876 (*vector2)[1] = *lambda2 - a;
877 }
878 else {
879 (*vector1)[0] = 1.0;
880 (*vector1)[1] = 0.0;
881 (*vector2)[0] = 0.0;
882 (*vector2)[1] = 1.0;
883 }
884
885 // Normalize eigenvectors
886 *vector1 /= norm(*vector1);
887 *vector2 /= norm(*vector2);
888
889 // Return
890 return;
891}
892
893
894/***********************************************************************//**
895 * @brief Set result FITS file
896 *
897 * Set the FITS file with the butterfly results.
898 ***************************************************************************/
900{
901 // Determine the number of energies
902 int nrows = m_energies.size();
903
904 // Allocate FITS table columns
905 GFitsTableDoubleCol col_energy("ENERGY", nrows);
906 GFitsTableDoubleCol col_intensity("INTENSITY", nrows);
907 GFitsTableDoubleCol col_intensity_min("INTENSITY_MIN", nrows);
908 GFitsTableDoubleCol col_intensity_max("INTENSITY_MAX", nrows);
909
910 // Set units of columns
911 col_energy.unit("TeV");
912 col_intensity.unit("ph/cm2/s/TeV");
913 col_intensity_min.unit("ph/cm2/s/TeV");
914 col_intensity_max.unit("ph/cm2/s/TeV");
915
916 // Fill columns and convert MeV units to TeV units
917 for (int i = 0; i < nrows; ++i) {
918 col_energy(i) = m_energies[i] * 1.0e-6;
919 col_intensity(i) = m_intensities[i] * 1.0e6;
920 col_intensity_min(i) = m_min_intensities[i] * 1.0e6;
921 col_intensity_max(i) = m_max_intensities[i] * 1.0e6;
922 }
923
924 // Create binary table
925 GFitsBinTable table;
926 table.extname("BUTTERFLY");
927
928 // Stamp header
929 stamp(table);
930
931 // Add keywords
932 table.card("INSTRUME", "CTA", "Name of Instrument");
933 table.card("TELESCOP", "CTA", "Name of Telescope");
934
935 // Append columns to table
936 table.append(col_energy);
937 table.append(col_intensity);
938 table.append(col_intensity_min);
939 table.append(col_intensity_max);
940
941 // Create the FITS file
942 m_fits.clear();
943 m_fits.append(table);
944
945 // Return
946 return;
947}
Butterfly calculation tool.
void copy_members(const ctbutterfly &app)
Copy class members.
void get_parameters(void)
Get application parameters.
bool m_apply_edisp
Apply energy dispersion?
void save(void)
Save butterfly diagram.
ctbutterfly & operator=(const ctbutterfly &app)
Assignment operator.
GChatter m_chatter
Chattiness.
GMatrixSparse m_covariance
Covariance matrix.
void create_fits(void)
Set result FITS file.
std::vector< double > m_energies
Energy values.
void eigenvectors(const double &a, const double &b, const double &c, const double &d, double *lambda1, double *lambda2, GVector *vector1, GVector *vector2)
Compute normalized eigenvectors and eigenvalues.
std::vector< double > m_intensities
Power law intensity.
std::vector< double > m_max_intensities
Maximum intensities.
std::string m_method
Computation method.
void init_members(void)
Initialise class members.
bool m_fit
Do fit?
GFilename m_outfile
Output ASCII file name.
GFits m_fits
FITS file holding butterfly.
int m_max_iter
Maximum number of iterations.
void process(void)
Computes the butterfly.
void gaussian_error_propagation(GModels &models)
Compute butterfly using Gaussian error propagation.
void free_members(void)
Delete class members.
void clear(void)
Clear ctbutterfly tool.
void ellipsoid_boundary(GModels &models)
Compute butterfly using the ellipsoid boundary method.
ctbutterfly(void)
Void constructor.
virtual ~ctbutterfly(void)
Destructor.
double m_confidence
Confidence level.
void check_model(void)
Check if sky model is valid.
std::vector< double > m_min_intensities
Minimum intensities.
std::string m_srcname
Name of source to compute butterfly.
GEbounds m_ebounds
Energy binning definition.
Base class for likelihood tools.
GOptimizerLM m_opt
Optimizer.
ctlikelihood & operator=(const ctlikelihood &app)
Assignment operator.
void free_members(void)
Delete class members.
void init_members(void)
Initialise class members.
void free_members(void)
Delete class members.
GObservations m_obs
Observation container.
const GObservations & obs(void) const
Return observation container.
void init_members(void)
Initialise class members.
void set_obs_statistic(const std::string &statistic)
Set fit statistic for CTA observations.
void setup_models(GObservations &obs, const std::string &name="")
Setup model container.
Definition ctool.cpp:545
GEbounds create_ebounds(void)
Create energy boundaries from user parameters.
Definition ctool.cpp:612
void free_members(void)
Delete class members.
Definition ctool.cpp:357
void log_observations(const GChatter &chatter, const GObservations &obs, const std::string &what="Observation")
Log observation container.
Definition ctool.cpp:1251
const bool & read_ahead(void) const
Signal whether parameters should be read ahead.
Definition ctool.hpp:177
void log_parameters(const GChatter &chatter)
Log application parameters.
Definition ctool.cpp:1208
void init_members(void)
Initialise class members.
Definition ctool.cpp:321
void setup_observations(GObservations &obs, const bool &response=true, const bool &list=true, const bool &cube=true)
Setup observation container.
Definition ctool.cpp:431
#define G_GET_PARAMETERS
Definition ctbin.cpp:42
#define G_CHECK_MODEL
Butterfly calculation tool interface definition.
#define CTBUTTERFLY_NAME