summaryrefslogtreecommitdiffstats
path: root/calc_mass_potential.py
diff options
context:
space:
mode:
authorAaron LI <aaronly.me@outlook.com>2016-07-13 19:02:00 +0800
committerAaron LI <aaronly.me@outlook.com>2016-07-13 19:02:00 +0800
commit41fb327b33da02d958a418d14e1d8928f660658b (patch)
treedf62e2c1ca37f663873df2975e0ff2b46827e601 /calc_mass_potential.py
parentf27f9326554802ef21250587f0f2252c6a1d7139 (diff)
downloadcexcess-41fb327b33da02d958a418d14e1d8928f660658b.tar.bz2
calc_mass.py = calc_mass_potential.py - potential calculation
Diffstat (limited to 'calc_mass_potential.py')
-rwxr-xr-xcalc_mass_potential.py667
1 files changed, 0 insertions, 667 deletions
diff --git a/calc_mass_potential.py b/calc_mass_potential.py
deleted file mode 100755
index bb49501..0000000
--- a/calc_mass_potential.py
+++ /dev/null
@@ -1,667 +0,0 @@
-#!/usr/bin/env python3
-#
-# Aaron LI
-# Created: 2016-06-24
-# Updated: 2016-07-11
-#
-# Change logs:
-# 2016-07-11:
-# * Use a default config to allow a minimal user config
-# 2016-07-10:
-# * Allow disable the calculation of potential profile
-# * Use class 'SmoothSpline' from module 'spline.py'
-# 2016-07-04:
-# * Remove unnecessary configuration options
-# * Update radii unit to be "kpc", mass unit to be "Msun"
-# 2016-06-29:
-# * Update "plot()" to support electron number density profile
-# 2016-06-28:
-# * Implement plot function
-# * Adjust integration tolerances and progress report
-# * Fit smoothing splines to profiles using R `mgcv::gam()`
-# 2016-06-27:
-# * Implement potential profile calculation:
-# methods 'calc_density_total()' and 'calc_potential()'
-# 2016-06-26:
-# * Add document on gravitational potential calculation
-# 2016-06-25:
-# * Rename method 'interpolate()' to 'fit_spline()'
-# * Use 'InterpolatedUnivariateSpline' instead of 'interp1d'
-# * Implement 'calc_mass_total()'
-# * Update documentation
-# 2016-06-24:
-# * Update method 'gen_radius()'
-#
-
-"""
-Calculate the (gas and gravitational) mass profile and gravitational
-potential profile from the electron number density profile, under the
-assumption of hydrostatic equilibrium.
-
-The electron density profile and temperature profile are required.
-
-Assuming that the gas is in hydrostatic equilibrium with the gravitational
-potential and a spherically-symmetric distribution of the gas, we can
-write the hydrostatic equilibrium equation (HEE) of the ICM as
-(ref.[1], eq.(6)):
- derivative(P_gas, r) / rho_gas = - derivative(phi, r)
- = - G M_tot(<r) / r^2
-where,
- phi: gravitational potential;
- G: gravitational constant;
- rho_gas: gas mass density:
- rho_gas = mu * m_atom * n_gas
- P_gas: gas pressure:
- P_gas = rho_gas * k_B * T_gas / (mu * m_atom) = n_gas * k_B * T_gas
- mu: mean molecular weight in a.m.u (i.e., m_atom) (~ 0.6)
- m_atom: atom mass unit
- n_gas: gas number density; sum of the electron and proton densities
- k_B: Boltzmann constant
- T_gas: gas temperature
-
-Solve the above equation, we can get the total mass of X-ray luminous
-galaxy clusters (ref.[1], eq.(7)):
- M_tot(<r) = - (k_B * T_gas(r) * r) / (mu * m_atom * G) *
- (derivative(log(T_gas), log(r)) +
- derivative(log(n_gas), log(r)))
-
-Note that the second part (i.e., the derivatives) is DIMENSIONLESS, since
- d(log(X)) = d(X) / X
-Also note that ('R' is a ratio constant):
- d(log(n_gas)) = d(log(R*n_e)) = d(log(n_e))
-And and 'log' derivative can be calculated as:
- derivative(log(X(r)), log(r)) = (r / X(r)) * derivative(X(r), r)
-
-Note that 'kT' has dimension of energy. Therefore, if the gas temperature
-is given in 'keV', then the 'kT' should be substitute as a whole.
-
-For example:
- (1.0 keV) * (1.0 kpc) / (0.6 * m_atom * G) ~= 3.7379e10 [ Msun ]
-which is consistent with the formula of (ref.[2], eq.(3))
-
-------------------------------------------------------------
-Gravitational potential profile calculation:
-
-Newton's theorems (ref.[3], Sec. 2.2.1):
-1. A body that is inside a spherical shell of matter experiences no net
- gravitational force from that shell.
-2. The gravitational force on a body that lies outside a spherical shell
- of matter is the same as it would be if all the shell's matter were
- concentrated into a point at its center.
-
-Therefore, the gravitational potential produced by a spherical shell of
-mass 'M' is:
- phi = (1) - G * M / R; (r <= R, i.e., inside the shell)
- (2) - G * M / r; (r > R, i.e., outside the shell)
-
-The total gravitational potential may be considered to be the sum of the
-potentials of spherical shells of mass
- dM(r) = 4 * pi * rho(r) * r^2 dr,
-so we may calculate the gravitational potential at 'R' generated by an
-arbitrary spherically symmetric density distribution 'rho(r)' by adding
-the contributions to the potential produced by shells
- (1) with r < R,
-and
- (2) with r > R.
-In this way, we obtain
- phi(R) = - (G/R) * \int_0^R dM(r) - G * \int_R^{\inf} dM(r)/r
- = - 4*pi*G * ((1/R) * \int_0^R r^2 * rho(r) dr +
- \int_R^{\inf} r * rho(r) dr)
-
-------------------------------------------------------------
-References:
-[1] Ettori et al., 2013, Space Science Review, 177, 119-154
-[2] Walker et al., 2012, MNRAS, 422, 3503
-[3] Tremaine & Binney, Galactic Dynamics, 2nd edition, 2008
-"""
-
-
-import argparse
-
-import numpy as np
-import astropy.units as au
-import astropy.constants as ac
-import scipy.integrate as integrate
-from scipy.misc import derivative
-from configobj import ConfigObj
-import matplotlib.pyplot as plt
-from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas
-from matplotlib.figure import Figure
-
-from astro_params import AstroParams, ChandraPixel
-from projection import Projection
-from spline import SmoothSpline
-
-plt.style.use("ggplot")
-
-config_default = """
-## Configuration for `calc_mass_potential.py`
-
-# electron density profile
-ne_profile = ne_profile.txt
-
-# cooling function profile
-cf_profile = coolfunc_profile.txt
-
-# temperature profile
-t_profile = t_profile.txt
-
-# number of data points for the output profiles (interpolation)
-num_dp = 1000
-
-# output gas mass profile
-m_gas_profile = mass_gas_profile.txt
-m_gas_profile_image = mass_gas_profile.png
-
-# output total (gravitational) mass profile
-m_total_profile = mass_total_profile.txt
-m_total_profile_image = mass_total_profile.png
-
-# output total mass density profile
-rho_total_profile = rho_total_profile.txt
-rho_total_profile_image = rho_total_profile.png
-
-# output gravitational potential profile
-# NOTE: to disable potential calculation, do not specified the output files
-potential_profile = potential_profile.txt
-potential_profile_image = potential_profile.png
-"""
-
-
-class DensityProfile:
- """
- Utilize the 3D (electron number or gas mass) density profile to
- calculate the following quantities:
- * 2D projected surface brightness (requires cooling function profile)
- * gas mass profile (integrated, M_gas(<r))
- * gravitational mass profile (M(<r); requires temperature profile)
- * gravitational potential profile (cut at the largest available radius)
-
- NOTE:
- * The radii should have unit [ kpc ]
- * The density should have unit [ cm^-3 ] or [ g cm^-3 ]
- """
- # available splines
- SPLINES = ["density", "electron", "rho_gas",
- "cooling_function", "temperature",
- "mass_total", "rho_total"]
- # allowed density profile types
- DENSITY_TYPES = ["electron", "gas"]
- # input density data: [r, r_err, d]
- r = None
- r_err = None
- d = None
- # electron number density
- ne = None
- # gas mass density
- rho_gas = None
- # cooling function profile
- cf_radius = None
- cf_value = None
- # temperature profile
- t_radius = None
- t_value = None
- # generated radial data points for profile calculation
- radius = None
- radius_err = None
- # gas mass profile: M_gas(<r); same length as the above 'radius'
- m_gas = None
- # total (gravitational) mass profile: M_total(<r)
- m_total = None
- # total mass density profile (required by potential calculation)
- rho_total = None
- # potential profile (cut at the largest available radius)
- potential = None
- # fitted spline to the profiles
- d_spline = None
- ne_spline = None
- rho_gas_spline = None
- cf_spline = None
- t_spline = None
- m_total_spline = None
- rho_total_spline = None
-
- def __init__(self, density, density_type="electron"):
- self.load_data(data=density, density_type=density_type)
-
- def load_data(self, data, density_type="electron"):
- if density_type not in self.DENSITY_TYPES:
- raise ValueError("invalid density_types: %s" % density_type)
- # 3-column density profile: r[kpc], r_err[kpc], density
- self.r = data[:, 0].copy()
- self.r_err = data[:, 1].copy()
- self.d = data[:, 2].copy()
- self.density_type = density_type
-
- def load_cf_profile(self, data):
- if data.shape[1] == 2:
- # 2-column cooling function profile: r[kpc], cf[flux/EM]
- self.cf_radius = data[:, 0].copy()
- self.cf_value = data[:, 1].copy()
- elif data.shape[1] == 3:
- # 3-column cooling function profile: r[kpc], r_err, cf[flux/EM]
- self.cf_radius = data[:, 0].copy()
- self.cf_value = data[:, 2].copy()
- else:
- raise ValueError("invalid cooling function profile data")
-
- def load_t_profile(self, data):
- if data.shape[1] == 2:
- # 2-column temperature profile: r[kpc], T[keV]
- self.t_radius = data[:, 0].copy()
- self.t_value = data[:, 1].copy()
- elif data.shape[1] == 3:
- # 3-column temperature profile: r[kpc], r_err[kpc], T[keV]
- self.t_radius = data[:, 0].copy()
- self.t_value = data[:, 2].copy()
- else:
- raise ValueError("invalid temperature profile data")
-
- def calc_density_electron(self):
- """
- Calculate the electron number density from the gas mass density
- if necessary, and fit a smoothing spline to it.
- """
- if self.density_type == "electron":
- self.ne = self.d.copy()
- elif self.density_type == "gas":
- self.ne = self.d / AstroParams.m_atom / AstroParams.mu_e
- # fit a smoothing spline
- self.fit_spline(spline="electron", log10=["x", "y"])
- return self.ne
-
- def calc_density_gas(self):
- """
- Calculate the gas mass density from the electron number density
- if necessary, and fit a smoothing spline to it.
- """
- if self.density_type == "electron":
- self.rho_gas = self.d * AstroParams.mu_e * AstroParams.m_atom
- elif self.density_type == "gas":
- self.rho_gas = self.d.copy()
- # fit a smoothing spline
- self.fit_spline(spline="rho_gas", log10=["x", "y"])
- return self.rho_gas
-
- def calc_brightness(self):
- """
- Project the electron number density or gas mass density profile
- to calculate the 2D surface brightness profile.
- """
- if self.cf_radius is None or self.cf_value is None:
- raise ValueError("cooling function profile missing")
- if self.cf_spline is None:
- self.fit_spline(spline="cooling_function", log10=[])
- #
- ne = self.calc_density_electron()
- # flux per unit volume
- cf_new = self.eval_spline(spline="cooling_function", x=self.r)
- flux = cf_new * ne ** 2 / AstroParams.ratio_ne_np
- # project the 3D flux into 2D brightness
- rout = (self.r + self.r_err) * au.kpc.to(au.cm)
- projector = Projection(rout)
- brightness = projector.project(flux)
- return brightness
-
- def fit_spline(self, spline, log10=[]):
- if spline not in self.SPLINES:
- raise ValueError("invalid spline: %s" % spline)
- #
- if spline == "density":
- # given density profile (either electron / gas mass density)
- x = self.r
- y = self.d
- spl = "d_spline"
- elif spline == "electron":
- # input electron number density profile
- x = self.r
- y = self.ne
- spl = "ne_spline"
- elif spline == "rho_gas":
- # input gas mass density profile
- x = self.r
- y = self.rho_gas
- spl = "rho_gas_spline"
- elif spline == "cooling_function":
- # input cooling function profile
- x = self.cf_radius
- y = self.cf_value
- spl = "cf_spline"
- elif spline == "temperature":
- # input temperature profile
- x = self.t_radius
- y = self.t_value
- spl = "t_spline"
- elif spline == "mass_total":
- # calculated total/gravitational mass profile
- x = self.radius
- y = self.m_total
- spl = "m_total_spline"
- elif spline == "rho_total":
- # calculated total mass density profile
- x = self.radius
- y = self.rho_total
- spl = "rho_total_spline"
- else:
- raise ValueError("invalid spline: %s" % spline)
- setattr(self, spl, SmoothSpline(x=x, y=y))
- getattr(self, spl).fit(log10=log10)
-
- def eval_spline(self, spline, x):
- """
- Evaluate the specified spline at the supplied positions.
- Also check whether the spline was fitted in the log-scale space,
- and transform the evaluated values if necessary.
- """
- if spline == "density":
- spl = self.d_spline
- elif spline == "electron":
- spl = self.ne_spline
- elif spline == "rho_gas":
- spl = self.rho_gas_spline
- elif spline == "cooling_function":
- spl = self.cf_spline
- elif spline == "temperature":
- spl = self.t_spline
- elif spline == "mass_total":
- spl = self.m_total_spline
- elif spline == "rho_total":
- spl = self.rho_total_spline
- else:
- raise ValueError("invalid spline: %s" % spline)
- return spl.eval(x)
-
- def gen_radius(self, num=1000):
- """
- Generate radial points for following mass and potential calculation.
-
- The generated radial points are logarithmic-evenly distributed.
-
- NOTE:
- The radii are first generated to determine the inner-most bin width,
- which is used to further divide the original inner-most bin (i.e.,
- radius 0 - r_out[0]), and then the other radii are generated with
- the constraint of given total number of points.
- """
- rout = self.r + self.r_err
- # first pass to determine the inner-most bin width
- rout_tmp = np.logspace(np.log10(rout[0]), np.log10(rout[-1]),
- num=num, base=10.0)
- bw = rout_tmp[1] - rout_tmp[0]
- # linear-evenly divide the first original bin (0 - rout[0])
- nbin = int(np.ceil(rout[0] / bw))
- rout_new1 = np.linspace(0.0, rout[0], num=nbin, endpoint=False)[1:]
- # second pass to generate the other radii
- rout_new2 = np.logspace(np.log10(rout[0]), np.log10(rout[-1]),
- num=(num-nbin+1), base=10.0)
- rout_new = np.concatenate([rout_new1, rout_new2])
- rin_new = np.concatenate([[0.0], rout_new[:-1]])
- self.radius = (rout_new + rin_new) / 2.0
- self.radius_err = (rout_new - rin_new) / 2.0
-
- def calc_mass_gas(self, verbose=False):
- """
- Calculate the gas mass profile, i.e., the mass of the gas within
- each radius.
-
- Reference: ref.[1], eq.(9)
- """
- def _f_rho_gas(r):
- return 4*np.pi * r**2 * self.eval_spline(spline="rho_gas", x=r)
- #
- m_gas = np.zeros(self.radius.shape)
- if verbose:
- print("Calculating the gas mass profile (#%d): ..." %
- len(self.radius), end="", flush=True)
- c = au.kpc.to(au.cm)**3 * au.g.to(au.solMass)
- for i, r in enumerate(self.radius):
- if verbose and (i+1) % 50 == 0:
- print("%d..." % (i+1), end="", flush=True)
- # enclosed gas mass [ Msun ]
- m_gas[i] = c * integrate.quad(_f_rho_gas, a=0.0, b=r,
- epsrel=1e-3)[0]
- if verbose:
- print("DONE!", flush=True)
- self.m_gas = m_gas
- return m_gas
-
- def calc_mass_total(self, verbose=True):
- """
- Calculate the total mass (i.e., gravitational mass) profile,
- under the assumption of hydrostatic equilibrium (HE).
-
- References: ref.[1], eq.(5,6,7)
- """
- if self.t_radius is None or self.t_value is None:
- raise ValueError("temperature profile required")
- if self.t_spline is None:
- self.fit_spline(spline="temperature", log10=[])
- #
- # calculate the coefficient of the total mass formula
- # M0 = (k_B * T_gas(r) * r) / (mu * m_atom * G)
- M0 = ((1.0*au.keV) * (1.0*au.kpc) /
- (AstroParams.mu * ac.u * ac.G)).to(au.solMass).value
- m_total = np.zeros(self.radius.shape)
- if verbose:
- print("Calculating the total mass profile (#%d): ..." %
- len(self.radius), end="", flush=True)
- for i, r in enumerate(self.radius):
- if verbose and (i+1) % 100 == 0:
- print("%d..." % (i+1), end="", flush=True)
- T = self.eval_spline(spline="temperature", x=r)
- dT_dr = derivative(lambda r: self.eval_spline("temperature", r),
- r, dx=0.01)
- ne = self.eval_spline(spline="electron", x=r)
- dne_dr = derivative(lambda r: self.eval_spline("electron", r),
- r, dx=0.01)
- # enclosed total mass [ Msun ]
- m_total[i] = - M0 * T * r * (((r / T) * dT_dr) +
- ((r / ne) * dne_dr))
- if verbose:
- print("DONE!", flush=True)
- self.m_total = m_total
- return m_total
-
- def calc_density_total(self, verbose=True):
- """
- Calculate the total mass density profile, which is required to
- calculate the following gravitational potential profile.
- """
- if self.m_total_spline is None:
- self.fit_spline(spline="mass_total", log10=["x", "y"])
- #
- if verbose:
- print("Calculating the total mass density profile ...")
- rho_total = np.zeros(self.radius.shape)
- # unit conversion: Msun/kpc^3 -> g/cm^3
- c = au.solMass.to(au.g) / au.kpc.to(au.cm)**3
- for i, r in enumerate(self.radius):
- dM_dr = derivative(lambda r: self.eval_spline("mass_total", r),
- r, dx=0.01)
- rho_total[i] = (dM_dr / (4 * np.pi * r**2)) * c
- self.rho_total = rho_total
- return rho_total
-
- def calc_potential(self, verbose=True):
- """
- Calculate the gravitational potential profile.
-
- NOTE:
- The integral in the potential formula can only be integrated
- to the largest radius of availability.
- This limitation will affect the absolute values of the calculated
- potentials, but not the shape of the potential profile.
- """
- def _int_inner(x):
- return x**2 * self.eval_spline(spline="rho_total", x=x)
-
- def _int_outer(x):
- return x * self.eval_spline(spline="rho_total", x=x)
-
- if self.rho_total is None:
- self.calc_density_total(verbose=verbose)
- if self.rho_total_spline is None:
- self.fit_spline(spline="rho_total", log10=["x", "y"])
- potential = np.zeros(self.radius.shape)
- if verbose:
- print("Calculating the potential profile (#%d): ..." %
- len(self.radius), end="", flush=True)
- r_max = max(self.radius)
- c = - 4 * np.pi * au.kpc.to(au.cm)**2
- for i, r in enumerate(self.radius):
- if verbose and (i+1) % 10 == 0:
- print("%d..." % (i+1), end="", flush=True)
- # total gravitational potential [ cm^2/s^2 ]
- potential[i] = c * ac.G.cgs.value * (
- (1/r) * integrate.quad(_int_inner, a=0.0, b=r,
- epsrel=1e-2)[0] +
- integrate.quad(_int_outer, a=r, b=r_max,
- epsrel=1e-2)[0])
- if verbose:
- print("DONE!", flush=True)
- self.potential = potential
- return potential
-
- def plot(self, profile, with_spline=True, ax=None, fig=None):
- x = self.radius
- xlabel = "3D Radius"
- xunit = "kpc"
- xscale = "log"
- yscale = "log"
- x_spl, y_spl = None, None
- if profile == "electron":
- x = self.r
- y = self.ne
- ylabel = "Electron number density"
- yunit = "cm$^{-3}$"
- if with_spline:
- x_spl = self.radius
- y_spl = self.eval_spline(spline="electron", x=self.radius)
- elif profile == "mass_gas":
- y = self.m_gas
- ylabel = "Gas mass"
- yunit = "M$_{\odot}$"
- elif profile == "mass_total":
- y = self.m_total
- ylabel = "Total mass"
- yunit = "M$_{\odot}$"
- elif profile == "rho_total":
- y = self.rho_total
- ylabel = "Total mass density"
- yunit = "g/cm$^3$"
- elif profile == "potential":
- y = self.potential
- ylabel = "Gravitational potential"
- yunit = "cm$^2$/s$^2$"
- yscale = "linear"
- else:
- raise ValueError("unknown profile name: %s" % profile)
- #
- if ax is None:
- fig, ax = plt.subplots(1, 1)
- ax.plot(x, y, linewidth=2)
- if with_spline and y_spl is not None:
- ax.plot(x_spl, y_spl, linewidth=2, linestyle="dashed")
- ax.set_xscale(xscale)
- ax.set_yscale(yscale)
- ax.set_xlim(min(x), max(x))
- y_min, y_max = min(y), max(y)
- y_min = y_min/1.2 if y_min > 0 else y_min*1.2
- y_max = y_max*1.2 if y_max > 0 else y_max/1.2
- ax.set_ylim(y_min, y_max)
- ax.set_xlabel(r"%s (%s)" % (xlabel, xunit))
- ax.set_ylabel(r"%s (%s)" % (ylabel, yunit))
- fig.tight_layout()
- return (fig, ax)
-
- def save(self, profile, outfile):
- if profile == "mass_gas":
- data = np.column_stack([self.radius,
- self.radius_err,
- self.m_gas])
- header = "radius[kpc] radius_err[kpc] mass_gas(<r)[Msun]"
- elif profile == "mass_total":
- data = np.column_stack([self.radius,
- self.radius_err,
- self.m_total])
- header = "radius[kpc] radius_err[kpc] mass_total(<r)[Msun]"
- elif profile == "rho_total":
- data = np.column_stack([self.radius,
- self.radius_err,
- self.rho_total])
- header = "radius[kpc] radius_err[kpc] density_total[g/cm^3]"
- elif profile == "potential":
- data = np.column_stack([self.radius,
- self.radius_err,
- self.potential])
- header = "radius[kpc] radius_err[kpc] potential[???]"
- else:
- raise ValueError("unknown profile name: %s" % profile)
- np.savetxt(outfile, data, header=header)
-
-
-def main():
- parser = argparse.ArgumentParser(
- description="Calculate the mass and potential profiles")
- parser.add_argument("config", nargs="?",
- help="additional config")
- args = parser.parse_args()
-
- config = ConfigObj(config_default.splitlines())
- if args.config is not None:
- config_user = ConfigObj(open(args.config))
- config.merge(config_user)
-
- ne_profile = np.loadtxt(config["ne_profile"])
- cf_profile = np.loadtxt(config["cf_profile"])
- t_profile = np.loadtxt(config["t_profile"])
-
- density_profile = DensityProfile(density=ne_profile,
- density_type="electron")
- density_profile.load_cf_profile(cf_profile)
- density_profile.load_t_profile(t_profile)
- density_profile.calc_density_electron()
- density_profile.calc_density_gas()
- density_profile.gen_radius(num=config.as_int("num_dp"))
-
- density_profile.calc_mass_gas(verbose=True)
- density_profile.save(profile="mass_gas",
- outfile=config["m_gas_profile"])
- fig = Figure(figsize=(10, 8))
- FigureCanvas(fig)
- ax = fig.add_subplot(1, 1, 1)
- density_profile.plot(profile="mass_gas", ax=ax, fig=fig)
- fig.savefig(config["m_gas_profile_image"], dpi=150)
-
- density_profile.calc_mass_total(verbose=True)
- density_profile.save(profile="mass_total",
- outfile=config["m_total_profile"])
- fig = Figure(figsize=(10, 8))
- FigureCanvas(fig)
- ax = fig.add_subplot(1, 1, 1)
- density_profile.plot(profile="mass_total", ax=ax, fig=fig)
- fig.savefig(config["m_total_profile_image"], dpi=150)
-
- density_profile.calc_density_total(verbose=True)
- density_profile.save(profile="rho_total",
- outfile=config["rho_total_profile"])
- fig = Figure(figsize=(10, 8))
- FigureCanvas(fig)
- ax = fig.add_subplot(1, 1, 1)
- density_profile.plot(profile="rho_total", ax=ax, fig=fig)
- fig.savefig(config["rho_total_profile_image"], dpi=150)
-
- outfile_potential = config["potential_profile"]
- if outfile_potential != "":
- density_profile.calc_potential(verbose=True)
- density_profile.save(profile="potential",
- outfile=outfile_potential)
- fig = Figure(figsize=(10, 8))
- FigureCanvas(fig)
- ax = fig.add_subplot(1, 1, 1)
- density_profile.plot(profile="potential", ax=ax, fig=fig)
- fig.savefig(config["potential_profile_image"], dpi=150)
-
-
-if __name__ == "__main__":
- main()