GammaLib 2.0.0
Loading...
Searching...
No Matches
GModelSpatialRadialProfileDMBurkert.cpp
Go to the documentation of this file.
1/***************************************************************************
2 * GModelSpatialRadialProfileDMBurkert.cpp - Burkert radial profile class *
3 * ----------------------------------------------------------------------- *
4 * copyright (C) 2016-2021 by Nathan Kelley-Hoskins *
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 GModelSpatialRadialProfileDMBurkert.cpp
23 * @brief Radial DM Burkert profile model class implementation
24 * @author Nathan Kelley-Hoskins
25 */
26
27/* __ Includes ___________________________________________________________ */
28#ifdef HAVE_CONFIG_H
29#include <config.h>
30#endif
31#include "GException.hpp"
32#include "GTools.hpp"
33#include "GMath.hpp"
34#include "GXmlElement.hpp"
37
38/* __ Constants __________________________________________________________ */
39
40/* __ Globals ____________________________________________________________ */
42const GModelSpatialRegistry g_radial_disk_registry(&g_radial_disk_seed);
43
44/* __ Method name definitions ____________________________________________ */
45#define G_READ "GModelSpatialRadialProfileDMBurkert::read(GXmlElement&)"
46#define G_WRITE "GModelSpatialRadialProfileDMBurkert::write(GXmlElement&)"
47
48/* __ Macros _____________________________________________________________ */
49
50/* __ Coding definitions _________________________________________________ */
51
52/* __ Debug definitions __________________________________________________ */
53
54
55/*==========================================================================
56 = =
57 = Constructors/destructors =
58 = =
59 ==========================================================================*/
60
61/***********************************************************************//**
62 * @brief Void constructor
63 *
64 * Constructs empty radial DMBurkert profile
65 ***************************************************************************/
68{
69 // Initialise members
71
72 // Return
73 return;
74}
75
76
77/***********************************************************************//**
78 * @brief XML constructor
79 *
80 * @param[in] xml XML element.
81 *
82 * Constructs radial DMBurkert profile model by extracting information from
83 * an XML element. See the read() method for more information about the
84 * expected structure of the XML element.
85 ***************************************************************************/
88{
89 // Initialise members
91
92 // Read information from XML element
93 read(xml);
94
95 // Return
96 return;
97}
98
99
100/***********************************************************************//**
101 * @brief Copy constructor
102 *
103 * @param[in] model Radial DMBurkert profile model.
104 *
105 * Copies radial DMBurkert profile model from another radial profile model.
106 ***************************************************************************/
109{
110 // Initialise members
111 init_members();
112
113 // Copy members
114 copy_members(model);
115
116 // Return
117 return;
118}
119
120
121/***********************************************************************//**
122 * @brief Destructor
123 *
124 * Destructs radial DMBurkert profile model.
125 ***************************************************************************/
127{
128 // Free members
129 free_members();
130
131 // Return
132 return;
133}
134
135
136/*==========================================================================
137 = =
138 = Operators =
139 = =
140 ==========================================================================*/
141
142/***********************************************************************//**
143 * @brief Assignment operator
144 *
145 * @param[in] model Radial DMBurkert profile model.
146 * @return Radial DMBurkert profile model.
147 *
148 * Assigns radial DMBurkert profile model.
149 ***************************************************************************/
151{
152 // Execute only if object is not identical
153 if (this != &model) {
154
155 // Copy base class members
157
158 // Free members
159 free_members();
160
161 // Initialise members
162 init_members();
163
164 // Copy members
165 copy_members(model);
166
167 } // endif: object was not identical
168
169 // Return
170 return *this;
171}
172
173
174/*==========================================================================
175 = =
176 = Public methods =
177 = =
178 ==========================================================================*/
179
180/***********************************************************************//**
181 * @brief Clear radial DMBurkert profile model
182 *
183 * Clears radial DMBurkert profile model.
184 ***************************************************************************/
186{
187 // Free class members
188 free_members();
192
193 // Initialise members
197 init_members();
198
199 // Return
200 return;
201}
202
203
204/***********************************************************************//**
205 * @brief Clone radial DMBurkert profile model
206 *
207 * @return Pointer to deep copy of radial DMBurkert profile model.
208 *
209 * Returns a deep copy of the radial DMBurkert profile model.
210 ***************************************************************************/
212{
213 // Clone radial disk model
214 return new GModelSpatialRadialProfileDMBurkert(*this);
215}
216
217/***********************************************************************//**
218 * @brief Return minimum model radius (in radians)
219 *
220 * @return Minimum model radius (in radians).
221 ***************************************************************************/
223{
224
225 // update precomputation cache
226 update();
227
228 // Return value
229 return m_theta_min.value();
230}
231
232/***********************************************************************//**
233 * @brief Return maximum model radius (in radians)
234 *
235 * @return Maximum model radius (in radians).
236 ***************************************************************************/
238{
239 // Update
240 update();
241
242 // initialize value
243 double theta = 0.0;
244
245 // If Earth is within the significant radius, then we must integrate
246 // the entire profile ...
248 theta = gammalib::pi;
249 }
250
251 // ... otherwise, if the halo is far enough away (further than the
252 // significant radius) then we just need to deal with the angles within
253 // the sphere of the significant radius
254 else {
255 theta = std::atan(m_mass_radius / m_halo_distance.value());
256 }
257
258 // Always chose the lesser of mass_radius theta and theta_max
260 if (theta > theta_max) {
261 theta = theta_max;
262 }
263
264 // Return value
265 return theta;
266}
267
268
269/***********************************************************************//**
270 * @brief Read model from XML element
271 *
272 * @param[in] xml XML element.
273 *
274 * Reads the DMBurkert radial profile model information from an XML element.
275 * The XML element shall have the format
276 *
277 * <spatialModel type="DMBurkertProfile">
278 * <parameter name="RA" scale=.. value=.. min=.. max=.. free=../>
279 * <parameter name="DEC" scale=.. value=.. min=.. max=.. free=../>
280 * <parameter name="ScaleRadius" scale=.. value=.. min=.. max=.. free=../>
281 * <parameter name="ScaleDensity" scale=.. value=.. min=.. max=.. free=../>
282 * <parameter name="HaloDistance" scale=.. value=.. min=.. max=.. free=../>
283 * <parameter name="ThetaMin" scale=.. value=.. min=.. max=.. free=../>
284 * <parameter name="ThetaMax" scale=.. value=.. min=.. max=.. free=../>
285 * <parameter name="CoreRadius" scale=.. value=.. min=.. max=.. free=../>
286 * </spatialModel>
287 *
288 ***************************************************************************/
290{
291 // Verify number of model parameters
293
294 // Read DMBurkert location
296
297 const GXmlElement* par1 = gammalib::xml_get_par(G_READ, xml, "ScaleRadius");
298 m_scale_radius.read(*par1);
299
300 const GXmlElement* par2 = gammalib::xml_get_par(G_READ, xml, "ScaleDensity");
301 m_scale_density.read(*par2);
302
303 const GXmlElement* par3 = gammalib::xml_get_par(G_READ, xml, "HaloDistance");
304 m_halo_distance.read(*par3);
305
306 const GXmlElement* par4 = gammalib::xml_get_par(G_READ, xml, "ThetaMin");
307 m_theta_min.read(*par4);
308
309 const GXmlElement* par5 = gammalib::xml_get_par(G_READ, xml, "ThetaMax");
310 m_theta_max.read(*par5);
311
312 const GXmlElement* par6 = gammalib::xml_get_par(G_READ, xml, "CoreRadius");
313 m_core_radius.read(*par6);
314
315 // Return
316 return;
317}
318
319
320/***********************************************************************//**
321 * @brief Write model into XML element
322 *
323 * @param[in] xml XML element into which model information is written.
324 *
325 * Writes the DMBurkert radial profile model information into an XML element.
326 * The XML element will have the format
327 *
328 * <spatialModel type="DMBurkertProfile">
329 * <parameter name="RA" scale=.. value=.. min=.. max=.. free=../>
330 * <parameter name="DEC" scale=.. value=.. min=.. max=.. free=../>
331 * <parameter name="ScaleRadius" scale=.. value=.. min=.. max=.. free=../>
332 * <parameter name="ScaleDensity" scale=.. value=.. min=.. max=.. free=../>
333 * <parameter name="HaloDistance" scale=.. value=.. min=.. max=.. free=../>
334 * <parameter name="ThetaMin" scale=.. value=.. min=.. max=.. free=../>
335 * <parameter name="ThetaMax" scale=.. value=.. min=.. max=.. free=../>
336 * <parameter name="CoreRadius" scale=.. value=.. min=.. max=.. free=../>
337 * </spatialModel>
338 ***************************************************************************/
340{
341 // Verify model type
343
344 // Write DMBurkert location
346
347 // Write Scale Radius parameter
348 GXmlElement* par1 = gammalib::xml_need_par(G_WRITE, xml, "ScaleRadius");
349 m_scale_radius.write(*par1);
350
351 // Write Scale Radius parameter
352 GXmlElement* par2 = gammalib::xml_need_par(G_WRITE, xml, "ScaleDensity");
353 m_scale_density.write(*par2);
354
355 // Write Halo Distance parameter
356 GXmlElement* par3 = gammalib::xml_need_par(G_WRITE, xml, "HaloDistance");
357 m_halo_distance.write(*par3);
358
359 // Write Halo Distance parameter
360 GXmlElement* par4 = gammalib::xml_need_par(G_WRITE, xml, "ThetaMin");
361 m_theta_min.write(*par4);
362
363 // Write Halo Distance parameter
364 GXmlElement* par5 = gammalib::xml_need_par(G_WRITE, xml, "ThetaMax");
365 m_theta_max.write(*par5);
366
367 // Write Core Radius parameter
368 GXmlElement* par6 = gammalib::xml_need_par(G_WRITE, xml, "CoreRadius");
369 m_core_radius.write(*par6);
370
371 // Return
372 return;
373}
374
375
376/***********************************************************************//**
377 * @brief Print information
378 *
379 * @param[in] chatter Chattiness.
380 * @return String containing model information.
381 ***************************************************************************/
383{
384 // Initialise result string
385 std::string result;
386
387 // Continue only if chatter is not silent
388 if (chatter != SILENT) {
389
390 // Append header
391 result.append("=== GModelSpatialRadialProfileDMBurkert ===");
392
393 // Append parameters
394 result.append("\n"+gammalib::parformat("Number of parameters"));
395 result.append(gammalib::str(size()));
396 for (int i = 0; i < size(); ++i) {
397 result.append("\n"+m_pars[i]->print(chatter));
398 }
399
400 } // endif: chatter was not silent
401
402 // Return result
403 return result;
404}
405
406
407/*==========================================================================
408 = =
409 = Private methods =
410 = =
411 ==========================================================================*/
412
413/***********************************************************************//**
414 * @brief Initialise class members
415 ***************************************************************************/
417{
418 // Initialise model type
419 m_type = "DMBurkertProfile";
420
421 // Initialise scale radius
423 m_scale_radius.name("ScaleRadius");
424 m_scale_radius.unit("kpc");
425 m_scale_radius.value(21.5); // default to GC scale radius
426 m_scale_radius.min(1.0e-6); // arbitrarily chosen :/
430 m_scale_radius.has_grad(false); // Radial components never have gradients
431
432 // Initialise scale density
434 m_scale_density.name("ScaleDensity");
435 m_scale_density.unit("GeV/cm^3");
436 m_scale_density.value(0.2); // GeV/cm3, default to GC scale density
437 m_scale_density.min(1.0e-6);
441 m_scale_density.has_grad(false); // Radial components never have gradients
442
443 // Initialise halo distance
445 m_halo_distance.name("HaloDistance");
446 m_halo_distance.unit("kpc");
447 m_halo_distance.value(7.94); // default to GC halo distance
448 m_halo_distance.min(1.0e-6); // arbitrarily chosen
452 m_halo_distance.has_grad(false); // Radial components never have gradients
453
454 // Initialise theta max
456 m_theta_min.name("ThetaMin");
457 m_theta_min.unit("degrees");
458 m_theta_min.value(1.0e-6);
459 m_theta_min.min(1.0e-10); // arbitrarily chosen
460 m_theta_min.fix(); // should always be fixed!
461 m_theta_min.scale(1.0);
463 m_theta_min.has_grad(false); // Radial components never have gradients
464
465 // Initialise theta max
467 m_theta_max.name("ThetaMax");
468 m_theta_max.unit("degrees");
469 m_theta_max.value(180.0); // can only go from halo center to opposite halo center
470 m_theta_max.min(1.0e-6); // arbitrarily chosen
471 m_theta_max.fix(); // should always be fixed!
472 m_theta_max.scale(1.0);
474 m_theta_max.has_grad(false); // Radial components never have gradients
475
476 // Initialise core radius
478 m_core_radius.name("CoreRadius");
479 m_core_radius.unit("kpc");
480 m_core_radius.value(0.5); // example: galactic center core
481 m_core_radius.min(0.0);
483 m_core_radius.scale(1.0);
485 m_core_radius.has_grad(false); // Radial components never have gradients
486
487 // Set parameter pointer(s)
488 m_pars.push_back(&m_scale_radius);
489 m_pars.push_back(&m_scale_density);
490 m_pars.push_back(&m_halo_distance);
491 m_pars.push_back(&m_theta_max);
492 m_pars.push_back(&m_theta_min);
493 m_pars.push_back(&m_core_radius);
494
495 // Initialize precomputation cache. Note that zero values flag
496 // uninitialised, as a zero radius is not meaningful
499 m_mass_radius = 0.0;
501
502 // Return
503 return;
504}
505
506
507/***********************************************************************//**
508 * @brief Copy class members
509 *
510 * @param[in] model Radial DMBurkert model.
511 *
512 * Copies class members from another radial profile model.
513 ***************************************************************************/
515{
516 // Copy members. We do not have to push back the members on the parameter
517 // stack as this should have been done by init_members() that was called
518 // before. Otherwise we would have sigma twice on the stack.
519 m_type = model.m_type; // Needed to conserve model type
523 m_theta_min = model.m_theta_min;
524 m_theta_max = model.m_theta_max;
526
527 // copy cache values
532
533 // Return
534 return;
535}
536
537
538/***********************************************************************//**
539 * @brief Delete class members
540 ***************************************************************************/
542{
543 // Return
544 return;
545}
546
547
548/***********************************************************************//**
549 * @brief Radial profile
550 *
551 * @param[in] theta Angular distance from DMBurkert centre (radians).
552 * @return Profile value.
553 ***************************************************************************/
555{
556 // Update precompuation cache
557 update();
558
559 // Initialize integral value
560 double value = 0.0;
561
562 // Set up integration limits
563 double los_min = m_halo_distance.value() - m_mass_radius;
564 double los_max = m_halo_distance.value() + m_mass_radius;
565
566 // Handle case where observer is within halo mass radius
567 if (los_min < 0.0) {
568 los_min = 0.0;
569 }
570
571 // Set up integral
574 theta,
576 GIntegral integral(&integrand);
577
578 // Compute value
579 value = integral.romberg(los_min, los_max) * m_scale_density_squared;
580
581 // Return value
582 return value;
583}
584
585
586/***********************************************************************//**
587 * @brief Kernel for halo density profile squared
588 *
589 * @param[in] los Distance from observer to point in space (meters).
590 * @return Halo density.
591 *
592 * Computes the value of an einasto halo density profile squared,
593 * at distance l from observer, at angle \f[\theta\f] from the halo center:
594 *
595 * \f[
596 * f(\theta, l) = \frac{r_{scale}^3}{ \left( r + r_{scale} \right)
597 * \left( r^2 + r_{scale}^2 \right)}
598 * \f]
599 *
600 * where
601 *
602 * \f[
603 * r = \sqrt{l^2+d^2-2ldCos(\theta)}
604 * \f]
605 *
606 * This profile is detailed in:
607 * Burkert, 1995
608 * "The Structure Of Dark Matter Halos In Dwarf Galaxies"
609 * The Astrophysical Journal, 447: L25–L28
610 * http://iopscience.iop.org/article/10.1086/309560/pdf
611 * Equation 2
612 *
613 ***************************************************************************/
615{
616 // Calculate the scale distance r, the ( distance from integration point
617 // to the halo center ) divided by ( the halo scale radius )
618
619 // first calculate the distance of the integration point from the halo
620 // center via the law of cosines
621 double r = los * los;
623 r -= 2.0 * los * m_halo_distance * std::cos(m_theta);
624 r = std::sqrt(r);
625
626 // If we have a core radius specified, all halo values inside this core
627 // radius should be the same as at the core radius itself.
628 if (r < m_core_radius) {
629 r = m_core_radius;
630 }
631
632 // Now that we've found out how far we are from the halo center,
633 // feed this radius to the burkert formula
634 double bot = (m_scale_radius + r);
635 bot *= (m_scale_radius*m_scale_radius) + (r*r);
637 f /= bot;
638
639 // Squared, for annihilating DM, would just be f if it was decaying dm
640 f = f * f;
641
642 // Return function value
643 return f;
644}
645
646
647/***********************************************************************//**
648 * @brief Update precomputation cache
649 *
650 * Computes the mass_radius calculation, determining the radius around
651 * the halo that contains 99.99% of the mass. For an Burket halo profile,
652 * this is just 80.0 * scale_radius.
653 ***************************************************************************/
655{
656 // Update if scale radius has changed
659
660 // Store last values
663
664 // perform precomputations
665 // set the mass radius to 80*scale_radius, meaning
666 // 99.99% of the mass is contained within the mass radius,
667 // and integration only needs to worry about whats inside this radius.
668 m_mass_radius = 80.0 * scale_radius();
670
671 }
672
673 // Return
674 return;
675}
676
677
678/***********************************************************************//**
679 * @brief Calculate Halo Mass Density
680 *
681 * @param[in] radius Distance from halo centre (kpc).
682 * @return Halo mass density.
683 *
684 * Calculates the halo's mass density at a given radial distance from the
685 * halo centre.
686 ***************************************************************************/
688{
689 // Initialize halo kernel with stored values. We use theta=0 to effectivly
690 // sample the halo radially
693 0.0,
695
696 // eval produces a unitless density^2, so we must take its square root
697 double density = std::sqrt(halo_shape.eval(m_halo_distance.value() + radius));
698
699 // Multiply in the missing scale density
700 density *= m_scale_density.value();
701
702 // Return halo mass density
703 return density;
704}
705
706
707/***********************************************************************//**
708 * @brief Calculate J-factor
709 *
710 * @param[in] angle Angle from halo center (radians).
711 * @return J-factor.
712 *
713 * Calculates the halo's J-factor at an angle from the halo center.
714 ***************************************************************************/
716{
717 // Integration settings
718 const double minradian = 0.0;
719 const int npoints = 200;
720
721 // Initialize other variables
722 double jfactor = 0.0 ;
723 double dr = (angle - minradian) / npoints ;
724
725 // Loop over different radii in the profile
726 for (int i = 0; i < npoints; ++i) {
727
728 // integration: Int[ profile(r) * r * dr ]
729 double r = minradian + (i * dr);
730 jfactor += profile_value(r) * r * dr;
731
732 }
733
734 // J-Factor = 2 * pi * Int[ profile(r) * r * dr , {r,minradian,angle} ]
736
737 // Return J-factor
738 return jfactor;
739}
#define G_WRITE
#define G_READ
Exception handler interface definition.
Mathematical function definitions.
const GModelSpatialRadialProfileDMBurkert g_radial_disk_seed
Dark Matter Burkert profile model class interface definition.
Spatial model registry class definition.
Gammalib tools definition.
GChatter
Definition GTypemaps.hpp:33
@ SILENT
Definition GTypemaps.hpp:34
double angle(const GVector &a, const GVector &b)
Computes angle between vectors.
Definition GVector.cpp:974
XML element node class interface definition.
GIntegral class interface definition.
Definition GIntegral.hpp:46
double romberg(std::vector< double > bounds, const int &order=5)
Perform Romberg integration.
void write(GXmlElement &xml) const
Set or update parameter attributes in XML element.
void read(const GXmlElement &xml)
Extract parameter attributes from XML element.
double eval(const double &los)
Kernel for halo density profile squared.
virtual GModelSpatialRadialProfileDMBurkert & operator=(const GModelSpatialRadialProfileDMBurkert &model)
Assignment operator.
GModelPar m_scale_density
Scale density of halo profile.
virtual double profile_value(const double &theta) const
Radial profile.
virtual void read(const GXmlElement &xml)
Read model from XML element.
virtual std::string print(const GChatter &chatter=NORMAL) const
Print information.
double mass_density(const double &radius) const
Calculate Halo Mass Density.
virtual void write(GXmlElement &xml) const
Write model into XML element.
virtual GModelSpatialRadialProfileDMBurkert * clone(void) const
Clone radial DMBurkert profile model.
virtual double theta_max(void) const
Return maximum model radius (in radians)
void copy_members(const GModelSpatialRadialProfileDMBurkert &model)
Copy class members.
double scale_density(void) const
Return scale density.
double scale_radius(void) const
Return scale radius.
GModelPar m_scale_radius
Scale radius of halo profile.
double jfactor(const double &angle) const
Calculate J-factor.
void update(void) const
Update precomputation cache.
virtual void clear(void)
Clear radial DMBurkert profile model.
GModelPar m_halo_distance
Distance from Earth to halo center.
virtual double theta_min(void) const
Return minimum model radius (in radians)
virtual GModelSpatialRadialProfile & operator=(const GModelSpatialRadialProfile &model)
Assignment operator.
void init_members(void)
Initialise class members.
void free_members(void)
Delete class members.
void free_members(void)
Delete class members.
virtual void write(GXmlElement &xml) const
Write model into XML element.
virtual void read(const GXmlElement &xml)
Read model from XML element.
void init_members(void)
Initialise class members.
Interface definition for the spatial model registry class.
std::string m_type
Spatial model type.
std::string type(void) const
Return model type.
std::vector< GModelPar * > m_pars
Parameter pointers.
void init_members(void)
Initialise class members.
int size(void) const
Return number of parameters.
void free_members(void)
Delete class members.
void free(void)
Free a parameter.
const double & scale(void) const
Return parameter scale.
bool has_grad(void) const
Signal if parameter gradient is computed analytically.
const std::string & unit(void) const
Return parameter unit.
double min(void) const
Return parameter minimum boundary.
void fix(void)
Fix a parameter.
double gradient(void) const
Return parameter gradient.
void clear(void)
Clear parameter.
double value(void) const
Return parameter value.
const std::string & name(void) const
Return parameter name.
XML element node class.
std::string parformat(const std::string &s, const int &indent=0)
Convert string in parameter format.
Definition GTools.cpp:1143
std::string str(const unsigned short int &value)
Convert unsigned short integer value into string.
Definition GTools.cpp:489
const GXmlElement * xml_get_par(const std::string &origin, const GXmlElement &xml, const std::string &name)
Return pointer to parameter with given name in XML element.
Definition GTools.cpp:1689
const double pi
Definition GMath.hpp:35
GXmlElement * xml_need_par(const std::string &origin, GXmlElement &xml, const std::string &name)
Return pointer to parameter with given name in XML element.
Definition GTools.cpp:1637
const double deg2rad
Definition GMath.hpp:43
void xml_check_parnum(const std::string &origin, const GXmlElement &xml, const int &number)
Checks number of parameters.
Definition GTools.cpp:1777
const double twopi
Definition GMath.hpp:36
void xml_check_type(const std::string &origin, GXmlElement &xml, const std::string &type)
Checks the model type.
Definition GTools.cpp:1819