├── bjet_core ├── __init__.py ├── bj_core.i ├── Makefile ├── processes_supp_core.h ├── params.txt ├── README.md └── bj_core.h ├── docs ├── requirements.txt ├── figures │ ├── corner_plot.png │ ├── model_and_data.png │ ├── convergence_time.png │ ├── particle_spectrum.png │ ├── chi_squared_plot_med.png │ ├── chi_squared_plot_all.jpeg │ ├── chi_squared_plot_best.png │ └── cooling_time_obs(Thomson).png ├── source │ ├── api │ │ ├── index.rst │ │ ├── bjet_mcmc.blazar_clean.rst │ │ ├── bjet_mcmc.blazar_mcmc.rst │ │ ├── bjet_mcmc.blazar_model.rst │ │ ├── bjet_mcmc.blazar_plots.rst │ │ ├── bjet_mcmc.blazar_utils.rst │ │ ├── bjet_mcmc.blazar_report.rst │ │ ├── bjet_mcmc.user_SED_plot.rst │ │ ├── bjet_mcmc.blazar_run_mcmc.rst │ │ ├── bjet_mcmc.blazar_initialize.rst │ │ ├── bjet_mcmc.blazar_properties.rst │ │ ├── cpp_bj_core.rst │ │ └── bjet_mcmc.rst │ ├── _templates │ │ ├── custom-class-template.rst │ │ └── custom-module-template.rst │ ├── index.rst │ ├── License.rst │ ├── install_and_run.rst │ ├── dependencies.rst │ ├── conf.py │ ├── configuration_file.rst │ ├── optimization.rst │ ├── data_format.rst │ ├── outputs.rst │ └── bjet_core.rst ├── Makefile └── make.bat ├── logo ├── Bjet_MCMC_logo_v1.pdf ├── Bjet_MCMC_logo_v1.png ├── Bjet_MCMC_logo_v2.png └── Bjet_MCMC_logo_small_v2.png ├── MANIFEST.in ├── bjet_mcmc ├── requirements.txt ├── __init__.py ├── run_mcmc.sh ├── blazar_clean.py ├── blazar_initialize.py ├── blazar_properties.py ├── run_Bjet_manual.py ├── blazar_mcmc.py ├── user_SED_plot.py ├── blazar_run_mcmc.py └── blazar_model.py ├── .readthedocs.yaml ├── setup.py ├── pyproject.toml ├── environment.yml ├── README.md ├── LICENSE ├── mcmc_config_template.txt ├── real_data └── J1010_SED_reduced.dat ├── parameter_files └── J1010.par └── .gitignore /bjet_core/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/requirements.txt: -------------------------------------------------------------------------------- 1 | sphinx==7.1.2 2 | sphinx-rtd-theme==1.3.0rc1 3 | breathe -------------------------------------------------------------------------------- /logo/Bjet_MCMC_logo_v1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ohervet/Bjet_MCMC/HEAD/logo/Bjet_MCMC_logo_v1.pdf -------------------------------------------------------------------------------- /logo/Bjet_MCMC_logo_v1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ohervet/Bjet_MCMC/HEAD/logo/Bjet_MCMC_logo_v1.png -------------------------------------------------------------------------------- /logo/Bjet_MCMC_logo_v2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ohervet/Bjet_MCMC/HEAD/logo/Bjet_MCMC_logo_v2.png -------------------------------------------------------------------------------- /docs/figures/corner_plot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ohervet/Bjet_MCMC/HEAD/docs/figures/corner_plot.png -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | recursive-include bjet_core * 2 | recursive-include bjet_mcmc * 3 | recursive-exclude */__pycache__ * 4 | -------------------------------------------------------------------------------- /docs/figures/model_and_data.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ohervet/Bjet_MCMC/HEAD/docs/figures/model_and_data.png -------------------------------------------------------------------------------- /logo/Bjet_MCMC_logo_small_v2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ohervet/Bjet_MCMC/HEAD/logo/Bjet_MCMC_logo_small_v2.png -------------------------------------------------------------------------------- /docs/figures/convergence_time.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ohervet/Bjet_MCMC/HEAD/docs/figures/convergence_time.png -------------------------------------------------------------------------------- /docs/figures/particle_spectrum.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ohervet/Bjet_MCMC/HEAD/docs/figures/particle_spectrum.png -------------------------------------------------------------------------------- /docs/figures/chi_squared_plot_med.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ohervet/Bjet_MCMC/HEAD/docs/figures/chi_squared_plot_med.png -------------------------------------------------------------------------------- /docs/figures/chi_squared_plot_all.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ohervet/Bjet_MCMC/HEAD/docs/figures/chi_squared_plot_all.jpeg -------------------------------------------------------------------------------- /docs/figures/chi_squared_plot_best.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ohervet/Bjet_MCMC/HEAD/docs/figures/chi_squared_plot_best.png -------------------------------------------------------------------------------- /docs/figures/cooling_time_obs(Thomson).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ohervet/Bjet_MCMC/HEAD/docs/figures/cooling_time_obs(Thomson).png -------------------------------------------------------------------------------- /docs/source/api/index.rst: -------------------------------------------------------------------------------- 1 | .. _api: 2 | 3 | API 4 | === 5 | 6 | .. toctree:: 7 | :maxdepth: 8 8 | 9 | cpp_bj_core 10 | bjet_mcmc 11 | -------------------------------------------------------------------------------- /docs/source/api/bjet_mcmc.blazar_clean.rst: -------------------------------------------------------------------------------- 1 | bjet\_mcmc.blazar\_clean module 2 | =============================== 3 | 4 | .. automodule:: bjet_mcmc.blazar_clean 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/api/bjet_mcmc.blazar_mcmc.rst: -------------------------------------------------------------------------------- 1 | bjet\_mcmc.blazar\_mcmc module 2 | ============================== 3 | 4 | .. automodule:: bjet_mcmc.blazar_mcmc 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/api/bjet_mcmc.blazar_model.rst: -------------------------------------------------------------------------------- 1 | bjet\_mcmc.blazar\_model module 2 | =============================== 3 | 4 | .. automodule:: bjet_mcmc.blazar_model 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/api/bjet_mcmc.blazar_plots.rst: -------------------------------------------------------------------------------- 1 | bjet\_mcmc.blazar\_plots module 2 | =============================== 3 | 4 | .. automodule:: bjet_mcmc.blazar_plots 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/api/bjet_mcmc.blazar_utils.rst: -------------------------------------------------------------------------------- 1 | bjet\_mcmc.blazar\_utils module 2 | =============================== 3 | 4 | .. automodule:: bjet_mcmc.blazar_utils 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /bjet_core/bj_core.i: -------------------------------------------------------------------------------- 1 | %module(packages="bjet_core.bj_core") bj_core 2 | %{ 3 | #define SWIG_FILE_WITH_INIT 4 | #include "bj_core.h" 5 | #include "processes_supp_core.h" 6 | %} 7 | %include bj_core.h 8 | %include processes_supp_core.h -------------------------------------------------------------------------------- /docs/source/api/bjet_mcmc.blazar_report.rst: -------------------------------------------------------------------------------- 1 | bjet\_mcmc.blazar\_report module 2 | ================================ 3 | 4 | .. automodule:: bjet_mcmc.blazar_report 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/api/bjet_mcmc.user_SED_plot.rst: -------------------------------------------------------------------------------- 1 | bjet\_mcmc.user\_SED\_plot module 2 | ================================= 3 | 4 | .. automodule:: bjet_mcmc.user_SED_plot 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/api/bjet_mcmc.blazar_run_mcmc.rst: -------------------------------------------------------------------------------- 1 | bjet\_mcmc.blazar\_run\_mcmc module 2 | =================================== 3 | 4 | .. automodule:: bjet_mcmc.blazar_run_mcmc 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/api/bjet_mcmc.blazar_initialize.rst: -------------------------------------------------------------------------------- 1 | bjet\_mcmc.blazar\_initialize module 2 | ==================================== 3 | 4 | .. automodule:: bjet_mcmc.blazar_initialize 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/api/bjet_mcmc.blazar_properties.rst: -------------------------------------------------------------------------------- 1 | bjet\_mcmc.blazar\_properties module 2 | ==================================== 3 | 4 | .. automodule:: bjet_mcmc.blazar_properties 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /bjet_mcmc/requirements.txt: -------------------------------------------------------------------------------- 1 | backports.statistics==0.1.0 2 | corner==2.2.1 3 | Cython==0.29.28 4 | dl==0.1.0 5 | emcee==3.1.1 6 | invoke==1.7.0 7 | matplotlib==3.3.4 8 | numpy==1.19.5 9 | ordereddict==1.1 10 | scipy==1.5.4 11 | tqdm==4.64.0 12 | wincertstore==0.2.1 13 | -------------------------------------------------------------------------------- /bjet_mcmc/__init__.py: -------------------------------------------------------------------------------- 1 | __all__ = [ 2 | "blazar_clean", 3 | "blazar_initialize", 4 | "blazar_model", 5 | "blazar_plots", 6 | "blazar_properties", 7 | "blazar_report", 8 | "blazar_run_mcmc", 9 | "blazar_utils", 10 | ] 11 | 12 | from bjet_mcmc.blazar_run_mcmc import mcmc 13 | from bjet_core import bj_core 14 | -------------------------------------------------------------------------------- /docs/source/api/cpp_bj_core.rst: -------------------------------------------------------------------------------- 1 | .. _bjet_core: 2 | 3 | bjet_core 4 | ========= 5 | 6 | ``bj_core02`` namespace 7 | ----------------------- 8 | 9 | .. doxygennamespace:: bj_core02 10 | :project: bjet_core 11 | :members: 12 | 13 | Functions and Variables in ``processes_supp_core`` 14 | -------------------------------------------------- 15 | 16 | .. doxygenfile:: processes_supp_core.cpp 17 | :project: bjet_core 18 | :path: bjet_core/processes_supp_core.cpp -------------------------------------------------------------------------------- /.readthedocs.yaml: -------------------------------------------------------------------------------- 1 | # Read the Docs configuration file for Sphinx projects 2 | # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details 3 | 4 | # Required 5 | version: 2 6 | 7 | # Set the OS, Python version and other tools you might need 8 | build: 9 | os: ubuntu-22.04 10 | tools: 11 | python: "3.10" 12 | 13 | python: 14 | install: 15 | - requirements: docs/requirements.txt 16 | 17 | sphinx: 18 | configuration: docs/source/conf.py 19 | -------------------------------------------------------------------------------- /docs/source/api/bjet_mcmc.rst: -------------------------------------------------------------------------------- 1 | bjet\_mcmc Package 2 | ================== 3 | 4 | Submodules 5 | ---------- 6 | .. toctree:: 7 | :maxdepth: 8 8 | 9 | bjet_mcmc.blazar_clean 10 | bjet_mcmc.blazar_initialize 11 | bjet_mcmc.blazar_mcmc 12 | bjet_mcmc.blazar_model 13 | bjet_mcmc.blazar_plots 14 | bjet_mcmc.blazar_properties 15 | bjet_mcmc.blazar_report 16 | bjet_mcmc.blazar_run_mcmc 17 | bjet_mcmc.blazar_utils 18 | bjet_mcmc.user_SED_plot 19 | -------------------------------------------------------------------------------- /bjet_mcmc/run_mcmc.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Execute the command to run the MCMC 4 | now=$(date +%s) 5 | log="output_b5.log" 6 | process_file="process_number_b5.log" 7 | OperatingSystem=$(uname -s) 8 | if [ "$OperatingSystem" = "Linux" ]; then 9 | nohup python blazar_run_mcmc.py > "$log" & 10 | fi 11 | 12 | if [ "$OperatingSystem" = "Darwin" ]; then 13 | nohup caffeinate python blazar_run_mcmc.py > "$log" & 14 | fi 15 | 16 | echo $! > "$process_file" 17 | echo "MCMC command started" 18 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line, and also 5 | # from the environment for the first two. 6 | SPHINXOPTS ?= 7 | SPHINXBUILD ?= sphinx-build 8 | SOURCEDIR = source 9 | BUILDDIR = build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 21 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup, Extension 2 | from setuptools.command.build_ext import build_ext 3 | 4 | bjet_core_ext_module = Extension( 5 | "bjet_core._bj_core", 6 | sources=[ 7 | "bjet_core/bj_core.i", 8 | "bjet_core/bj_core.cpp", 9 | "bjet_core/processes_supp_core.cpp", 10 | ], 11 | swig_opts=[ 12 | "-c++", 13 | "-py3", 14 | "-outdir", 15 | "bjet_core", 16 | ], 17 | ) 18 | 19 | setup( 20 | cmdclass={"build_ext": build_ext}, 21 | ext_modules=[bjet_core_ext_module], 22 | packages=[ 23 | "bjet_core", 24 | "bjet_mcmc", 25 | ], # these are the names of the packages to import in a python session. 26 | include_package_data=True, 27 | ) 28 | -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | set SOURCEDIR=source 11 | set BUILDDIR=build 12 | 13 | if "%1" == "" goto help 14 | 15 | %SPHINXBUILD% >NUL 2>NUL 16 | if errorlevel 9009 ( 17 | echo. 18 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 19 | echo.installed, then set the SPHINXBUILD environment variable to point 20 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 21 | echo.may add the Sphinx directory to PATH. 22 | echo. 23 | echo.If you don't have Sphinx installed, grab it from 24 | echo.http://sphinx-doc.org/ 25 | exit /b 1 26 | ) 27 | 28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 29 | goto end 30 | 31 | :help 32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 33 | 34 | :end 35 | popd 36 | -------------------------------------------------------------------------------- /docs/source/_templates/custom-class-template.rst: -------------------------------------------------------------------------------- 1 | {{ fullname | escape | underline}} 2 | 3 | .. currentmodule:: {{ module }} 4 | 5 | .. autoclass:: {{ objname }} 6 | :members: <-- add at least this line 7 | :show-inheritance: <-- plus I want to show inheritance... 8 | :inherited-members: <-- ...and inherited members too 9 | 10 | {% block methods %} 11 | .. automethod:: __init__ 12 | 13 | {% if methods %} 14 | .. rubric:: {{ _('Methods') }} 15 | 16 | .. autosummary:: 17 | {% for item in methods %} 18 | ~{{ name }}.{{ item }} 19 | {%- endfor %} 20 | {% endif %} 21 | {% endblock %} 22 | 23 | {% block attributes %} 24 | {% if attributes %} 25 | .. rubric:: {{ _('Attributes') }} 26 | 27 | .. autosummary:: 28 | {% for item in attributes %} 29 | ~{{ name }}.{{ item }} 30 | {%- endfor %} 31 | {% endif %} 32 | {% endblock %} -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "Bjet-MCMC" #This is the name of the package to install/uninstall with pip 3 | version = "1.1.0" 4 | description = "BJet-MCMC Python module" 5 | readme = "README.md" 6 | classifiers = ["Programming Language :: Python :: 3", 7 | "License :: OSI Approved :: GNU General Public License v3 (GPLv3)", 8 | "Operating System :: Unix", ] 9 | 10 | [project.urls] 11 | Homepage = "https://bjet-mcmc.readthedocs.io/en/latest/" 12 | Issues = "https://github.com/Ohervet/Bjet_MCMC/issues" 13 | 14 | [project.scripts] 15 | blazar_run_mcmc = "bjet_mcmc.blazar_run_mcmc:main_cli" 16 | blazar_mcmc = "bjet_mcmc.blazar_mcmc:main_cli" 17 | blazar_clean = "bjet_mcmc.blazar_clean:clean" 18 | blazar_initialize = "bjet_mcmc.blazar_initialize:initialize" 19 | 20 | [build-system] 21 | requires = ["setuptools>=61.0.0", "wheel"] 22 | build-backend = "setuptools.build_meta" 23 | 24 | [tool.setuptools.package-data] 25 | bjet_mcmc = ["*.sh"] 26 | bjet_core = ["*"] 27 | -------------------------------------------------------------------------------- /environment.yml: -------------------------------------------------------------------------------- 1 | name: bjet-mcmc 2 | channels: 3 | - astropy 4 | - conda-forge 5 | - defaults 6 | dependencies: 7 | - blas=1.0 8 | - brotli=1.0.9 9 | - brotli-bin=1.0.9 10 | - ca-certificates=2022.6.15 11 | - certifi=2022.6.15 12 | - corner=2.1.0 13 | - cycler=0.11.0 14 | - emcee=3.1.2 15 | - fonttools=4.25.0 16 | - freetype=2.11.0 17 | - giflib=5.2.1 18 | - invoke=1.7.1 19 | - jpeg=9e 20 | - kiwisolver=1.4.2 21 | - lcms2=2.12 22 | - libbrotlicommon=1.0.9 23 | - libbrotlidec=1.0.9 24 | - libbrotlienc=1.0.9 25 | - libcxx=12.0.0 26 | - libffi=3.4.2 27 | - libgfortran5=11.2.0 28 | - libopenblas=0.3.20 29 | - libpng=1.6.37 30 | - libtiff=4.2.0 31 | - libwebp=1.2.2 32 | - libwebp-base=1.2.2 33 | - lz4-c=1.9.3 34 | - matplotlib=3.5.1 35 | - matplotlib-base=3.5.1 36 | - munkres=1.1.4 37 | - ncurses=6.3 38 | - numpy=1.23.1 39 | - numpy-base=1.23.1 40 | - openssl=1.1.1q 41 | - packaging=21.3 42 | - pillow=9.2.0 43 | - pip=22.1.2 44 | - pyparsing=3.0.4 45 | - python=3.8.13 46 | - python-dateutil=2.8.2 47 | - readline=8.1.2 48 | - scipy=1.8.0 49 | - setuptools=61.2.0 50 | - swig=4.0.2 51 | - six=1.16.0 52 | - sqlite=3.39.2 53 | - tk=8.6.12 54 | - tornado=6.1 55 | - wheel=0.37.1 56 | - xz=5.2.5 57 | - zlib=1.2.12 58 | - zstd=1.5.2 59 | - pip: 60 | - astropy==5.2.1 61 | - h5py==3.7.0 62 | - tqdm==4.64.0 63 | prefix: /opt/homebrew/Caskroom/miniconda/base/envs/bjet-mcmc 64 | -------------------------------------------------------------------------------- /docs/source/index.rst: -------------------------------------------------------------------------------- 1 | Welcome to Bjet_MCMC 2 | =================================== 3 | 4 | **Bjet_MCMC** is a tool to automatically model multiwavelength spectral energy distributions of blazars, considering one-zone synchrotron-self-Compton (SSC) model with or without the addition of external inverse-Compton process from the thermal emission of the nucleus. It also contains manual fitting functionalities for multi-zone SSC modeling. 5 | This tool is built as an MCMC python wrapper around the C++ code Bjet. 6 | 7 | License 8 | ------- 9 | The code is licensed under a :doc:`BSD 3-Clause License `. 10 | 11 | 12 | Acknowledgments and citation 13 | ---------------------------- 14 | - If you use this code in a scientific publication or communication, please cite the paper `Hervet et al. 2024 `_ . 15 | - For any use of the multi-zones SSC option, please also cite `Hervet at al. 2015 `_ . 16 | - To reference a specific version, you can also use Zenodo citation: 17 | 18 | .. image:: https://zenodo.org/badge/DOI/10.5281/zenodo.10070356.svg 19 | :target: https://doi.org/10.5281/zenodo.10070356 20 | 21 | 22 | 23 | .. note:: 24 | 25 | This project is under active development. 26 | 27 | Contents 28 | -------- 29 | .. toctree:: 30 | 31 | install_and_run 32 | dependencies 33 | configuration_file 34 | data_format 35 | outputs 36 | bjet_core 37 | optimization 38 | api/index 39 | 40 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Bjet_MCMC 2 | 3 |

4 | 5 |

6 | 7 | **Bjet_MCMC** is a tool to automatically model multiwavelength spectral energy distributions of blazars, considering one-zone synchrotron-self-Compton (SSC) model with or without the addition of external inverse-Compton process from the thermal emission of the nucleus. It also contains manual fitting functionalities for multi-zone SSC modeling. 8 | This tool is built as an MCMC python wrapper around the C++ code Bjet. 9 | 10 | The original contributors of Bjet_MCMC are: Olivier Hervet, Caitlin Johnson, and Adrian Youngquist 11 | 12 | Other contributors: Deivid Ribeiro, Aaron Danen 13 | 14 | License 15 | ------- 16 | The code is licensed under a [BSD-3-Clause License](LICENSE). 17 | 18 | 19 | Acknowledgments and citation 20 | ------- 21 | - If you use this code in a scientific publication or communication, please cite the paper [Hervet et al. 2024](https://iopscience.iop.org/article/10.3847/1538-4357/ad09c0). 22 | - For any use of the multi-zones SSC option, please also cite [Hervet at al. 2015](https://ui.adsabs.harvard.edu/abs/2015A%26A...578A..69H/abstract). 23 | - To reference a specific version, you can also use Zenodo citation: [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.10070356.svg)](https://zenodo.org/doi/10.5281/zenodo.10070356) 24 | 25 | 26 | 27 | 28 | 29 | 30 | ## Installation and running Bjet_MCMC: 31 | 32 | The official documentation is now moved on [readthedocs.io](https://bjet-mcmc.readthedocs.io/en/latest/). 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2024, Olivier Hervet 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | 2. Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | 3. Neither the name of the copyright holder nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 23 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | -------------------------------------------------------------------------------- /docs/source/License.rst: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | ==================== 3 | 4 | .. _BSD 3-Clause License: 5 | 6 | Copyright (c) 2024, Olivier Hervet 7 | 8 | Redistribution and use in source and binary forms, with or without 9 | modification, are permitted provided that the following conditions are met: 10 | 11 | 1. Redistributions of source code must retain the above copyright notice, this 12 | list of conditions and the following disclaimer. 13 | 14 | 2. Redistributions in binary form must reproduce the above copyright notice, 15 | this list of conditions and the following disclaimer in the documentation 16 | and/or other materials provided with the distribution. 17 | 18 | 3. Neither the name of the copyright holder nor the names of its 19 | contributors may be used to endorse or promote products derived from 20 | this software without specific prior written permission. 21 | 22 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 23 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 25 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 26 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 28 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 29 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 30 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 | 33 | -------------------------------------------------------------------------------- /docs/source/_templates/custom-module-template.rst: -------------------------------------------------------------------------------- 1 | {{ fullname | escape | underline}} 2 | 3 | .. automodule:: {{ fullname }} 4 | 5 | {% block attributes %} 6 | {% if attributes %} 7 | .. rubric:: Module Attributes 8 | 9 | .. autosummary:: 10 | :toctree: <-- add this line 11 | {% for item in attributes %} 12 | {{ item }} 13 | {%- endfor %} 14 | {% endif %} 15 | {% endblock %} 16 | 17 | {% block functions %} 18 | {% if functions %} 19 | .. rubric:: {{ _('Functions') }} 20 | 21 | .. autosummary:: 22 | :toctree: <-- add this line 23 | {% for item in functions %} 24 | {{ item }} 25 | {%- endfor %} 26 | {% endif %} 27 | {% endblock %} 28 | 29 | {% block classes %} 30 | {% if classes %} 31 | .. rubric:: {{ _('Classes') }} 32 | 33 | .. autosummary:: 34 | :toctree: <-- add this line 35 | :template: custom-class-template.rst <-- add this line 36 | {% for item in classes %} 37 | {{ item }} 38 | {%- endfor %} 39 | {% endif %} 40 | {% endblock %} 41 | 42 | {% block exceptions %} 43 | {% if exceptions %} 44 | .. rubric:: {{ _('Exceptions') }} 45 | 46 | .. autosummary:: 47 | :toctree: <-- add this line 48 | {% for item in exceptions %} 49 | {{ item }} 50 | {%- endfor %} 51 | {% endif %} 52 | {% endblock %} 53 | 54 | {% block modules %} 55 | {% if modules %} 56 | .. rubric:: Modules 57 | 58 | .. autosummary:: 59 | :toctree: 60 | :template: custom-module-template.rst <-- add this line 61 | :recursive: 62 | {% for item in modules %} 63 | {{ item }} 64 | {%- endfor %} 65 | {% endif %} 66 | {% endblock %} -------------------------------------------------------------------------------- /mcmc_config_template.txt: -------------------------------------------------------------------------------- 1 | # Configuration file for running mcmc 2 | 3 | # description: 4 | description=J1010 5 | 6 | # folder label: 7 | folder_label=J1010 8 | 9 | # eic (True/False): 10 | eic=False 11 | 12 | # Data file: 13 | data_file=real_data/J1010_SED_reduced.dat 14 | 15 | # Number of steps: 16 | n_steps=3600 17 | 18 | # Number of walkers: 19 | n_walkers=30 20 | 21 | # Discard number: 22 | discard = 200 23 | 24 | # Parallel processing (True/False): 25 | parallel=True 26 | 27 | # If parallel processing, # of cores (will use # of cores - 1 if not specified) 28 | cores=15 29 | 30 | # use tau variability (boolean): 31 | use_variability=False 32 | 33 | # tau variability (in hours): 34 | tau_variability = 24 35 | 36 | # redshift 37 | redshift = 0.143 38 | 39 | # Custom alpha2 limits (True/False, , ) val1 and val2 optional 40 | custom_alpha2_limits=False 41 | 42 | #to freeze a parameter to a given value, replace null by the values you want it to be frozen 43 | delta = null # doppler factor linear 44 | K = null # particle density [cm^-3] log10 45 | n1 = null # first particle index linear 46 | n2 = null # second particle index linear 47 | gamma_min = null # low-energy cutoff log10 48 | gamma_max = null # high-energy cutoff log10 49 | gamma_break = null # energy break log10 50 | B = null # magnetic field strength [G] log10 51 | R = null # blob radius [cm] log10 52 | #-----------------------------------------------------------------------# 53 | #-----------------------Additional params for EIC-----------------------# 54 | bb_temp = null # Black body temp of disk [K] log10 55 | l_nuc = null # Nucleus luminosity [ergs/s] log10 56 | tau = null # Frac of luminosity scattered log10 57 | blob_dist = null # Distance of blob from SMBH[cm] log10 58 | -------------------------------------------------------------------------------- /docs/source/install_and_run.rst: -------------------------------------------------------------------------------- 1 | Installation and running Bjet_MCMC 2 | ================================== 3 | 4 | .. _installation: 5 | 6 | Installation 7 | ------------ 8 | You first need to clone the Bjet_MCMC Github repo in your local computer with 9 | 10 | .. code-block:: console 11 | 12 | $ git clone https://github.com/Ohervet/Bjet_MCMC 13 | 14 | Ensure all dependencies are installed, see :doc:`dependencies`. Recommended: create the conda env "bjet-mcmc" from ``environment.yml`` using 15 | 16 | .. code-block:: console 17 | 18 | $ conda env create -f environment.yml 19 | 20 | If you use an updated version of Bjet_MCMC from a previously installed version, you might need to update your conda environment, with 21 | 22 | .. code-block:: console 23 | 24 | $ conda env update -f environment.yml --prune 25 | 26 | Then load your environment with 27 | 28 | .. code-block:: console 29 | 30 | $ conda activate bjet-mcmc 31 | 32 | 33 | 34 | Running Bjet_MCMC for the first time 35 | ------------------------------------ 36 | 37 | 1. Create a copy of ``mcmc_config_template.txt`` called `mcmc_config.txt`. For information and customized configuration files, see :doc:`configuration_file`. 38 | 2. Ensure the data file is well formatted and is at the relative path specified in ``mcmc_config.txt``, see :doc:`data_format`. 39 | 3. Install Bjet-mcmc with ``pip install -e .`` (in top directory, where setup.py and pyproject.toml are located). This also compiles the C++ code (see :doc:`bjet_core`). 40 | 4. First time use: execute ``blazar_initialize`` with ``python blazar_initialize.py`` or ``python3 blazar_initialize.py`` depending on your Python setup. This creates all necessary folders. If using ``python blazar_initialize.py``, you must be in the directory `bjet_mcmc`. 41 | 5. Execute ``blazar_run_mcmc`` with ``blazar_run_mcmc``, ``python blazar_run_mcmc.py`` or ``python3 blazar_run_mcmc.py`` depending on your Python setup. If using ``python blazar_run_mcmc.py``, you must be in the directory `bjet_mcmc`. 42 | 6. Retrieve and check the results (see :doc:`outputs`). 43 | 44 | -------------------------------------------------------------------------------- /docs/source/dependencies.rst: -------------------------------------------------------------------------------- 1 | 2 | Dependencies 3 | ============ 4 | 5 | .. _dependencies: 6 | 7 | **Recommended:** create conda env from ``environment.yml`` using ``conda env create -f environment.yml`` 8 | 9 | 10 | ``emcee`` 11 | --------- 12 | 13 | - conda: 14 | 15 | .. code-block:: console 16 | 17 | $ conda install -c conda-forge emcee 18 | 19 | - pip: 20 | 21 | ``emcee`` recommends calling 22 | 23 | .. code-block:: console 24 | 25 | $ pip install -U setuptools setuptools_scm pep517 26 | $ pip install -U emcee 27 | - ``emcee`` installation `documentation `_ 28 | 29 | ``scipy`` 30 | --------- 31 | 32 | - pip: 33 | 34 | .. code-block:: console 35 | 36 | $ python -m pip install -U scipy 37 | 38 | - conda: 39 | 40 | .. code-block:: console 41 | 42 | $ conda install -c conda-forge scipy 43 | 44 | - `scipy` installation `documentation `_ 45 | 46 | ``invoke`` 47 | ---------- 48 | - pip: 49 | 50 | .. code-block:: console 51 | 52 | $ python -m pip install invoke 53 | 54 | - conda: 55 | 56 | .. code-block:: console 57 | 58 | $ conda install -c conda-forge invoke 59 | 60 | 61 | ``matplotlib`` 62 | -------------- 63 | - conda: 64 | 65 | .. code-block:: console 66 | 67 | $ conda install matplotlib 68 | 69 | - pip: 70 | 71 | .. code-block:: console 72 | 73 | $ python -m pip install -U matplotlib 74 | 75 | - `matplotlib` installation `documentation `_ 76 | 77 | ``corner`` 78 | ---------- 79 | - conda: 80 | 81 | .. code-block:: console 82 | 83 | $ conda install -c astropy corner 84 | 85 | - pip: 86 | 87 | .. code-block:: console 88 | 89 | $ python -m pip install corner 90 | - `corner` installation `documentation `_ 91 | 92 | ``tqdm`` 93 | -------- 94 | - pip: 95 | 96 | .. code-block:: console 97 | 98 | $ python -m pip install tqdm 99 | 100 | ``h5py`` 101 | -------- 102 | - pip: 103 | 104 | .. code-block:: console 105 | 106 | $ python -m pip install h5py 107 | -------------------------------------------------------------------------------- /bjet_mcmc/blazar_clean.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | """ 4 | The clean function removes all data files and removes parameter files not named 5 | params.txt. 6 | """ 7 | import os 8 | 9 | from bjet_mcmc.blazar_properties import * 10 | 11 | __all__ = ["clean"] 12 | 13 | 14 | def clean(data=True, data_folder=None, parameter_files=True, parameter_folder=None): 15 | """ 16 | Clean function documentation. Remove data files and remove parameter files not named params.txt 17 | 18 | :param data: A boolean indicating whether to clean data files. Default is True. 19 | :type data: bool 20 | :param data_folder: The folder where the data files are stored. If None, the default data folder will be used. 21 | :type data_folder: str or None 22 | :param parameter_files: A boolean indicating whether to clean parameter files. Default is True. 23 | :type parameter_files: bool 24 | :param parameter_folder: The folder where the parameter files are stored. If None, the default parameter folder will be used. 25 | :type parameter_folder: str or None 26 | :return: A boolean indicating whether the clean operation was successful. 27 | :rtype: bool 28 | 29 | """ 30 | success = True 31 | if data: 32 | if data_folder is None: 33 | data_folder = DATA_FOLDER 34 | if os.path.exists(BASE_PATH + data_folder): 35 | files = [ 36 | f for f in os.listdir(BASE_PATH + data_folder) if f.endswith(".dat") 37 | ] 38 | for f in files: 39 | os.remove(BASE_PATH + data_folder + "/" + f) 40 | else: 41 | success = False 42 | 43 | if parameter_files: 44 | if parameter_folder is None: 45 | parameter_folder = PARAMETER_FOLDER 46 | if os.path.exists(BASE_PATH + parameter_folder): 47 | files = [ 48 | f 49 | for f in os.listdir(BASE_PATH + parameter_folder) 50 | if f.endswith(".txt") 51 | ] 52 | for f in files: 53 | if f != "params.txt": 54 | os.remove(BASE_PATH + parameter_folder + "/" + f) 55 | else: 56 | success = False 57 | return success 58 | 59 | 60 | if __name__ == "__main__": 61 | clean() 62 | -------------------------------------------------------------------------------- /real_data/J1010_SED_reduced.dat: -------------------------------------------------------------------------------- 1 | !E(eV) F(ergcm-2s-1) delta_E(-) delta_E(+) delta_F(-) delta_F(+) instrument 2 | 1.5548 8.48E-012 0.17621 0.16843 4.11E-013 4.11E-013 ATOM 3 | 1.9356 8.97E-012 0.16314 0.27997 2.03E-012 3.52E-012 ATOM 4 | 2.8327 1.05E-011 0.35125 0.43236 3.03E-012 5.25E-012 ATOM 5 | 2.2558 1.02E-011 0.18799 0.22558 2.87E-013 2.87E-013 Swift-UVOT 6 | 2.8198 8.63E-012 0.33838 0.44523 1.96E-013 1.96E-013 Swift-UVOT 7 | 3.5449 7.52E-012 0.44311 0.59081 1.83E-013 1.83E-013 Swift-UVOT 8 | 4.0023 9.83E-012 0.90052 1.6373 2.36E-013 2.36E-013 Swift-UVOT 9 | 5.1696 1.30E-011 0.73852 1.0339 6.32E-013 6.32E-013 Swift-UVOT 10 | 5.6396 1.10E-011 0.86763 1.2532 2.14E-013 2.14E-013 Swift-UVOT 11 | 395 9.65E-012 85 85 1.14E-012 1.14E-012 Swift-XRT 12 | 520 1.13E-011 40 40 1.42E-012 1.42E-012 Swift-XRT 13 | 625 7.70E-012 65 65 8.18E-013 8.18E-013 Swift-XRT 14 | 750 7.95E-012 60 60 7.81E-013 7.81E-013 Swift-XRT 15 | 855 7.92E-012 45 45 8.42E-013 8.42E-013 Swift-XRT 16 | 955 6.19E-012 55 55 6.44E-013 6.44E-013 Swift-XRT 17 | 1065 7.15E-012 55 55 7.01E-013 7.01E-013 Swift-XRT 18 | 1185 6.79E-012 65 65 6.37E-013 6.37E-013 Swift-XRT 19 | 1310 7.11E-012 60 60 7.02E-013 7.02E-013 Swift-XRT 20 | 1440 5.75E-012 70 70 6.10E-013 6.10E-013 Swift-XRT 21 | 1585 5.82E-012 75 75 6.36E-013 6.36E-013 Swift-XRT 22 | 1760 5.62E-012 100 100 6.04E-013 6.04E-013 Swift-XRT 23 | 2030 4.69E-012 170 170 5.15E-013 5.15E-013 Swift-XRT 24 | 2420 5.45E-012 220 220 6.26E-013 6.26E-013 Swift-XRT 25 | 3040 4.14E-012 400 400 4.87E-013 4.87E-013 Swift-XRT 26 | 4280 3.41E-012 840 840 4.10E-013 4.10E-013 Swift-XRT 27 | 5820 2.81E-012 700 700 6.79E-013 6.79E-013 Swift-XRT 28 | 1698600000 1.29E-012 698650000 1186800000 0.00E+000 0.00E+000 Fermi-LAT 29 | 4901300000 1.92E-012 2015900000 3424300000 5.59E-013 5.59E-013 Fermi-LAT 30 | 14142000000 1.43E-012 5816600000 9880400000 7.64E-013 7.64E-013 Fermi-LAT 31 | 40806000000 2.27E-012 16783000000 28509000000 1.41E-012 1.41E-012 Fermi-LAT 32 | 117740000000 9.22E-012 48426000000 82259000000 0.00E+000 0.00E+000 Fermi-LAT 33 | 296236003888.79 1.57E-012 88136003888.790 125463996111.20 4.25E-013 4.40E-013 H.E.S.S. 34 | 600355719552.99 5.25E-013 178655719552.99 254344280447.00 2.14E-013 2.22E-013 H.E.S.S. 35 | 1216727524961.9 2.22E-013 362027524961.93 515372475038.06 1.71E-013 1.81E-013 H.E.S.S. 36 | 2465769133556.5 4.30E-013 733669133556.50 1044430866443.5 1.75E-013 1.90E-013 H.E.S.S. 37 | -------------------------------------------------------------------------------- /docs/source/conf.py: -------------------------------------------------------------------------------- 1 | # Configuration file for the Sphinx documentation builder. 2 | 3 | # -- Project information 4 | import os, sys 5 | import subprocess 6 | 7 | # Check if we're running on Read the Docs' servers 8 | read_the_docs_build = os.environ.get("READTHEDOCS", None) == "True" 9 | 10 | if read_the_docs_build: 11 | print("Building on Read the Docs") 12 | if not os.path.exists("./_build/doxygen"): 13 | os.makedirs("./_build/doxygen") 14 | dox_cmd = "doxygen Doxyfile" 15 | subprocess.run(dox_cmd, shell=True) 16 | breathe_projects = {"bjet_core": "_build/doxygen/xml"} 17 | breathe_default_project = "bjet_core" 18 | breathe_default_members = ("members", "undoc-members") 19 | 20 | sys.path.insert( 21 | 0, os.path.abspath("../../bjet_mcmc") 22 | ) # Source code dir relative to this file 23 | sys.path.insert( 24 | 0, os.path.abspath("../../bjet_core") 25 | ) # Source code dir relative to this file 26 | sys.path.insert(0, os.path.abspath("../../")) # Source code dir relative to this file 27 | 28 | release = "0.2" 29 | version = "0.2.1" 30 | 31 | # -- General configuration 32 | 33 | extensions = [ 34 | "sphinx.ext.duration", 35 | "sphinx.ext.doctest", 36 | "sphinx.ext.autodoc", 37 | "sphinx.ext.autosummary", 38 | "sphinx.ext.intersphinx", 39 | "breathe", 40 | ] 41 | 42 | autosummary_generate = True # Turn on sphinx.ext.autosummary 43 | 44 | intersphinx_mapping = { 45 | "python": ("https://docs.python.org/3/", None), 46 | "sphinx": ("https://www.sphinx-doc.org/en/master/", None), 47 | } 48 | intersphinx_disabled_domains = ["std"] 49 | pygments_style = "sphinx" 50 | 51 | templates_path = ["_templates"] 52 | exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"] 53 | autodoc_mock_imports = [ 54 | "numpy", 55 | "emcee", 56 | "scipy", 57 | "swig", 58 | "tqdm", 59 | "matplotlib", 60 | "bjet_core", 61 | "corner", 62 | "astropy", 63 | ] 64 | 65 | # -- Options for HTML output 66 | 67 | html_theme = "sphinx_rtd_theme" 68 | html_static_path = ["_static"] 69 | html_logo = "../../logo/Bjet_MCMC_logo_small_v2.png" 70 | html_theme_options = { 71 | "logo_only": True, 72 | "display_version": False, 73 | } 74 | html_context = { 75 | 'display_github': True, 76 | 'github_user': 'Ohervet', 77 | 'github_repo': 'Bjet_MCMC', 78 | 'github_version': 'master/docs/source/', 79 | } 80 | 81 | # -- Options for EPUB output 82 | epub_show_urls = "footnote" 83 | -------------------------------------------------------------------------------- /bjet_core/Makefile: -------------------------------------------------------------------------------- 1 | # Executable name will be bj_core. 2 | # Modified from Makefile for bjet02 in Feb 2022 for use in MCMC by Sarah Youngquist 3 | # Change: changed file names to match mcmc, added support for MacOS Darwin, 4 | # optimization is more aggressive, using O3 instead of O2. 5 | SHELL=/bin/sh 6 | 7 | OperatingSystem:=$(shell uname -s) 8 | 9 | ifeq (${OperatingSystem},Linux) 10 | ARCH=linux 11 | endif 12 | 13 | ifeq (${OperatingSystem},OSF1) 14 | ARCH=alphacxx6 15 | endif 16 | 17 | # ADDED SY 18 | ifeq (${OperatingSystem},Darwin) 19 | ARCH=darwin 20 | endif 21 | 22 | Dir=./ 23 | oDir=./ 24 | iDir=-Wall 25 | lDir=-lm 26 | 27 | CXX = 28 | 29 | PROG = bj_core 30 | NO = 02 31 | 32 | ObjSuf =o 33 | SrcSuf =cpp 34 | ExeSuf =exe 35 | DllSuf =so 36 | OutPutOpt =-o 37 | 38 | SRC = processes_supp_core.$(SrcSuf) $(PROG).$(SrcSuf) 39 | 40 | .SUFFIXES: .$(SrcSuf) 41 | 42 | OBJ = $(SRC:.$(SrcSuf)=.$(ObjSuf)) 43 | 44 | ifeq ($(ARCH),alphacxx6) 45 | #Alpha/OSF with cxx6 46 | $(Attention, je fais n importe quoi...) 47 | CXX =cxx 48 | CXXFLAGS=-O0 -gall 49 | 50 | LD =cxx 51 | LDFLAGS =-O 52 | SOFLAGS =-Wl,-expect_unresolved,*-shared 53 | endif 54 | 55 | ifeq ($(ARCH),linux) 56 | CXX =g++ 57 | CXXFLAGS=-O3 -Wall -g -fPIC 58 | LD =g++ 59 | LDFLAGS =-O3 -Wall -lm -g -fPIC 60 | SOFLAGS =-shared 61 | endif 62 | 63 | # ADDED SY 64 | ifeq ($(ARCH),darwin) 65 | CXX =g++ 66 | CXXFLAGS=-O3 -Wall -g -fPIC 67 | LD =g++ 68 | LDFLAGS =-O3 -Wall -lm -g -fPIC 69 | SOFLAGS =-shared 70 | endif 71 | 72 | ifeq ($(CXX),) 73 | $(error $(ARCH) invalid architecture) 74 | endif 75 | 76 | LIBS =$(SYSLIBS) 77 | GLIBS =$(SYSLIBS) 78 | 79 | 80 | #--------------------------------------------- 81 | .$(SrcSuf).$(ObjSuf): 82 | $(CXX) $(CXXFLAGS) -c $< 83 | 84 | ### 85 | $(PROG): $(OBJ) 86 | $(LD) $(OutPutOpt) $@ $^ $(LDFLAGS) $(LIBS) 87 | @echo "" 88 | @echo "$@ done" 89 | @echo "" 90 | 91 | clean: 92 | @rm -f $(OBJ) $(PROG) 93 | @rm -f *.o $(PROG2) 94 | @echo "" 95 | @echo "cleaned" 96 | @echo "" 97 | 98 | cleandata: 99 | @rm -f ./data/*.dat 100 | @echo "" 101 | @echo "data removed" 102 | @echo "" 103 | 104 | 105 | #----------host gal-----------# 106 | 107 | CXX=g++ 108 | Dir=./ 109 | oDir=./ 110 | iDir=-Wall 111 | lDir=-lm 112 | 113 | PROG1=gal 114 | 115 | N1=eg02 116 | 117 | gal: 118 | EXOBJS1=\ 119 | $(oDir)$(N1).o \ 120 | 121 | $(PROG1): $(EXOBJS1) 122 | $(CXX) -o $@ $(EXOBJS1) $(lDir) 123 | 124 | $(oDir)/$(N1).o: $(N1).cpp 125 | $(CXX) -c $< $(iDir) -o $@ 126 | 127 | 128 | -------------------------------------------------------------------------------- /docs/source/configuration_file.rst: -------------------------------------------------------------------------------- 1 | Configuration file 2 | ================== 3 | 4 | .. _configuration file: 5 | 6 | The default configuration file is ``mcmc_config.txt`` in the main directory. 7 | If you would like to use a different file, you can enter the absolute path of your configuration file as an argument when running ``blazar_run_mcmc.py``, 8 | such as 9 | 10 | .. code-block:: console 11 | 12 | $ python blazar_run_mcmc.py /home/myconfigfile.txt 13 | 14 | There is a file named ``mcmc_config_template.txt`` as an example. Make a copy of this file named ``mcmc_config.txt``. 15 | This file is automatically in ``.gitignore`` since it changes locally. 16 | 17 | Notes: 18 | 19 | - Labels must be exactly as listed in the configuration file. 20 | 21 | - ``data_file`` is the *relative path* from the Bjet_MCMC directory to the file with data. 22 | 23 | Example of a configuration file 24 | ------------------------------- 25 | 26 | (file named ``mcmc_config.txt``, can be modified):: 27 | 28 | 29 | # Configuration file for running mcmc 30 | 31 | # description: 32 | description=J1010 33 | 34 | # folder label: 35 | folder_label=J1010 36 | 37 | # eic (True/False): 38 | eic=False 39 | 40 | # Data file: 41 | data_file=real_data/J1010_SED_reduced.dat 42 | 43 | # Number of steps: 44 | n_steps=1000 45 | 46 | # Number of walkers: 47 | n_walkers=100 48 | 49 | # Discard number: 50 | discard = 200 51 | 52 | # Parallel processing (True/False): 53 | parallel=True 54 | 55 | # If parallel processing, # of cores (will use # of cores - 1 if not specified) 56 | cores=15 57 | 58 | # use tau variability (boolean): 59 | use_variability=False 60 | 61 | # tau variability (in hours): 62 | tau_variability = 24 63 | 64 | # redshift 65 | redshift = 0.143 66 | 67 | # Custom alpha2 limits (True/False, , ) val1 and val2 optional 68 | custom_alpha2_limits=False 69 | 70 | #to freeze a parameter to a given value, replace null with the values you want it to be frozen 71 | delta = null # doppler factor linear 72 | K = null # particle density [cm^-3] log10 73 | n1 = null # first particle index linear 74 | n2 = null # second particle index linear 75 | gamma_min = null # low-energy cutoff log10 76 | gamma_max = null # high-energy cutoff log10 77 | gamma_break = null # energy break log10 78 | B = null # magnetic field strength [G] log10 79 | R = null # blob radius [cm] log10 80 | #-----------------------------------------------------------------------# 81 | #-----------------------Additional params for EIC-----------------------# 82 | bb_temp = null # Black body temp of disk [K] log10 83 | l_nuc = null # Nucleus luminosity [ergs/s] log10 84 | tau = null # Frac of luminosity scattered log10 85 | blob_dist = null # Distance of blob from SMBH[cm] log10 86 | 87 | -------------------------------------------------------------------------------- /bjet_core/processes_supp_core.h: -------------------------------------------------------------------------------- 1 | // exact copy of the processes_supp from bjet 2 | #ifndef __PROCESSES_SUPP_V02_H_ 3 | #define __PROCESSES_SUPP_V02_H_ 4 | /** @file */ 5 | 6 | extern double Simpson(double func[], double ics[], int res, int start, int end); 7 | extern double linint(double x, double xvec[], int xdim, double x_min, double x_max); 8 | 9 | extern double j_syn(double (*elec_spec)(double), double gamma_min, double gamma_max, double nu, double B, int prec1, int prec2); 10 | extern double k_esa(double (*elec_spec)(double), double gamma_min, double gamma_max, double nu, double B, int prec1, int prec2); 11 | extern double CylTransfEquat(double I_inp, double jj, double kk, double ll); 12 | extern double SphTransfEquat(double jj, double kk, double ll); 13 | extern double Intens2Flux(double Intens, double Radius, double Doppler, double z, double Hubble); 14 | extern double CylIntens2Flux(double Intens1, double Intens2, double Radius, double Length, double Doppler, double z, double Hubble, double Theta); 15 | extern double RingIntens2Flux(double Intens, double InnRadius, double OutRadius, double Doppler, double z, double Hubble, int check); 16 | extern double FreqTransS2O(double nu, double Doppler, double z); 17 | extern double FreqTransO2S(double nu, double Doppler, double z); 18 | extern double j_com(double (*elec_spec)(double), double gamma_min, double gamma_max, 19 | double I_rad[], double nu_rad_min, double nu_rad_max, int nu_rad_dim, 20 | double nu, int prec1, int prec2); 21 | extern double tau_IRA_Kneiske(double nu, double zz, int range); 22 | extern double tau_IRA_Franceschini(double nu, double zz); 23 | extern double tau_IRA_Finke(double nu, double zz); 24 | extern double tau_IRA_Franceschini17(double nu, double zz); 25 | extern double tau_IIR(double nu, double z, int level); 26 | //extern double gg_abs_ssc(double (*elec_spec)(double), double gamma_min, double gamma_max, double nu, double B, double r, int sph_cyl, int prec1, int prec2); 27 | extern double gg_abs(double nu_c, double I_syn[], int nu_dim, double nu_min, double nu_max, int prec1, int prec2); 28 | //extern double gg_abs_ssc2nd(double (*elec_spec)(double), double gamma_min, double gamma_max, double nu, double I_rad2nd[], double nu_rad_min, double nu_rad_max, int nu_rad_dim, double r, int sph_cyl, int prec1, int prec2); 29 | //extern double gg_abs_eic(double (*elec_spec)(double), double gamma_min, double gamma_max, double I_rad[], double nu_rad_min, double nu_rad_max, int nu_rad_dim, double nu_c, double r, int sph_cyl, int prec1, int prec2); 30 | //extern double sig_gg(double,double, double NU[]); 31 | extern double sigma_gg(double nu_s, double nu_c); 32 | extern double intgl(double (*func)(double), double a, double b, int n, int m); 33 | extern double Planck(double nu_BB, double T_BB); 34 | 35 | //extern double LuminDist(const double redshift); 36 | extern double Distance_Luminosity(double z, double H0, double WM); 37 | extern double piondecay(double energy);// E^2 dN/dE eV/(cm^2.s) 38 | extern double piondecaytest(double energy);// E^2 dN/dE eV/(cm^2.s) 39 | 40 | extern void setHadronicParameters(); 41 | extern void setHadronicParametersTest(); 42 | 43 | extern double piondecay_ahaprecise_electron(double energy); // production of secondary electrons from pion decay 44 | 45 | extern void energetics(); 46 | 47 | #endif 48 | -------------------------------------------------------------------------------- /parameter_files/J1010.par: -------------------------------------------------------------------------------- 1 | ------------------------------------------------------------------------------ 2 | Transformation_parameters 3 | ------------------------------------------------------------------------------ 4 | 0.143 redshift 5 | 69.6 Hubble_constant______________________________________[km/(sMpc)] 6 | 0.57 angle_to_the_line_of_sight___________________________[degrees] 7 | ------------------------------------------------------------------------------ 8 | Blob_parameters 9 | ------------------------------------------------------------------------------ 10 | 8.38e+01 Doppler_factor 11 | 4.24e+03 Particle_density_____________________________________[1/cm^3] 12 | 2.56 First_slope_of_particle_energy_spectrum 13 | 3.75 Second_slope_of_particle_energy_spectrum 14 | 9.22 Minimum_electrons_energy 15 | 1.99e+06 Maximum_electrons_energy 16 | 2.13e+05 Break_in_electrons_energy_spectrum 17 | 1.71e-03 Magnetic_field_______________________________________[G] 18 | 1.40e+17 Radius_of_emitting_region____________________________[cm] 19 | 0 length_of_emitting_region_(0_for_spherical_geometry)_[cm] 20 | 1 absorption_by_EBL_(0=NO___1=YES) 21 | 9.0e+17 distance_blob_SMBH_(host_galaxy_frame)_______________[cm] 22 | ------------------------------------------------------------------------------ 23 | Extern_Inverse_Compton_parameter 24 | ------------------------------------------------------------------------------ 25 | 0 compute_EIC_(0=NO___1=YES) 26 | 0 compute_X_corona_(0=NO___1=YES) 27 | 4.0e+4 Disk_black_body_temperature__________________________[K] 28 | 2.0e+4 Torus_black_body_temperature_________________________[K] 29 | 3.0e+43 Luminosity_of_the_disk_______________________________[erg/s] 30 | 9.0e-5 Tau___fraction_of_L_disk_reprocessed_isotropically 31 | 5.5e+20 Luminosity_of_the_torus______________________________[erg/s] 32 | 9.0e-5 Tau___fraction_of_L_tor_reprocessed_isotropically 33 | ------------------------------------------------------------------------------ 34 | Jet_parameters 35 | ------------------------------------------------------------------------------ 36 | 0 compute_JET_(0=NO___1=YES) 37 | 3.0 Doppler_factor 38 | 1.0e+2 Initial_particle_density_____________________________[1/cm^3] 39 | 2.1 Slope_of_particle_energy_spectrum 40 | 1.0e+3 Minimum_electrons_energy 41 | 2.0e+4 Maximum_electrons_energy 42 | 0.08 Initial_magnetic_field_______________________________[G] 43 | 1.2e+17 Inner_radius_(host_galaxy_frame)_____________________[cm] 44 | 300 Jet_length_(host_galaxy_frame)_______________________[pc] 45 | 1.0 Half-opening_angle_of_jet_(host_galaxy_frame)________[deg] 46 | 50 number_of_slices 47 | ------------------------------------------------------------------------------ 48 | Numerical_parameters 49 | ------------------------------------------------------------------------------ 50 | 99 number_of_spectral_points 51 | 50000000.0 minimal_frequency____________________________________[Hz] 52 | 1e+29 maximal_frequency____________________________________[Hz] 53 | test_bj prefix_of_file_names 54 | -------------------------------------------------------------------------------- /bjet_core/params.txt: -------------------------------------------------------------------------------- 1 | ------------------------------------------------------------------------------ 2 | Transformation_parameters 3 | ------------------------------------------------------------------------------ 4 | 0.143 redshift 5 | 71.0 Hubble_constant______________________________________[km/(sMpc)] 6 | 0.57 angle_to_the_line_of_sight___________________________[degrees] 7 | ------------------------------------------------------------------------------ 8 | Blob_parameters 9 | ------------------------------------------------------------------------------ 10 | 65.37453205394094 Doppler_factor 11 | 3055.866878840638 Particle_density_____________________________________[1/cm^3] 12 | 2.4382523182828253 First_slope_of_particle_energy_spectrum 13 | 3.878040661446401 Second_slope_of_particle_energy_spectrum 14 | 4932.538308851102 Minimum_electrons_energy 15 | 2345682.606499136 Maximum_electrons_energy 16 | 150445.38661768168 Break_in_electrons_energy_spectrum 17 | 0.0042239695613087 Magnetic_field_______________________________________[G] 18 | 8.13346533849387e+16 Radius_of_emitting_region____________________________[cm] 19 | 0 length_of_emitting_region_(0_for_spherical_geometry)_[cm] 20 | 1 absorption_by_EBL_(0=NO___1=YES) 21 | 9.0e+17 distance_blob_SMBH_(host_galaxy_frame)_______________[cm] 22 | ------------------------------------------------------------------------------ 23 | Extern_Inverse_Compton_parameter 24 | ------------------------------------------------------------------------------ 25 | 1 compute_EIC_(0=NO___1=YES) 26 | 0 compute_X_corona_(0=NO___1=YES) 27 | 4.0e+4 Disk_black_body_temperature__________________________[K] 28 | 2.0e+4 Torus_black_body_temperature_________________________[K] 29 | 3.0e+43 Luminosity_of_the_disk_______________________________[erg/s] 30 | 9.0e-5 Tau___fraction_of_L_disk_reprocessed_isotropically 31 | 5.5e+20 Luminosity_of_the_torus______________________________[erg/s] 32 | 9.0e-5 Tau___fraction_of_L_tor_reprocessed_isotropically 33 | ------------------------------------------------------------------------------ 34 | Jet_parameters 35 | ------------------------------------------------------------------------------ 36 | 0 compute_JET_(0=NO___1=YES) 37 | 3.0 Doppler_factor 38 | 1.0e+2 Initial_particle_density_____________________________[1/cm^3] 39 | 2.1 Slope_of_particle_energy_spectrum 40 | 1.0e+3 Minimum_electrons_energy 41 | 2.0e+4 Maximum_electrons_energy 42 | 0.08 Initial_magnetic_field_______________________________[G] 43 | 1.2e+17 Inner_radius_(host_galaxy_frame)_____________________[cm] 44 | 300 Jet_length_(host_galaxy_frame)_______________________[pc] 45 | 1.0 Half-opening_angle_of_jet_(host_galaxy_frame)________[deg] 46 | 50 number_of_slices 47 | ------------------------------------------------------------------------------ 48 | Numerical_parameters 49 | ------------------------------------------------------------------------------ 50 | 99 number_of_spectral_points 51 | 50000000.0 minimal_frequency____________________________________[Hz] 52 | 1e+29 maximal_frequency____________________________________[Hz] 53 | eic prefix_of_file_names 54 | -------------------------------------------------------------------------------- /docs/source/optimization.rst: -------------------------------------------------------------------------------- 1 | Computing Optimization Advice 2 | ============================= 3 | Users can configure the underlying MCMC algorithm. Most importantly, users 4 | must define the number of walkers, and the number of steps each walker will 5 | take. We have tested many different combinations of steps and walkers, to 6 | come up with the following guidelines. 7 | 8 | Configuration 9 | ------------- 10 | - Emcee moves 11 | 12 | We are yet to find any computational improvements from modifying the walker 13 | moves passed to the emcee library. After significant testing, we found the 14 | default ``StretchMove()`` with parameter ``a=2`` to still be the best. 15 | 16 | - Walkers and Steps 17 | 18 | Intuitvely, having more walkers and steps will increase computation time. 19 | More iterations over the MCMC algorithm will result in better results. As to 20 | the ratio between steps and walkers, we suggest having **120 times as many 21 | steps as walkers.** 22 | 23 | Testing 24 | ------- 25 | Tests were conducted such that num_steps*num_walkers = 300,000. We observed 26 | minimum convergence time when we tested 6000 steps and 50 walkers. And find 27 | our conclusion that 6000/50 = 120 steps/walker. We assume that this ratio 28 | remains close to optimal as users scale the number of walkers and steps. 29 | 30 | .. image:: ../figures/convergence_time.png 31 | :width: 800 32 | 33 | On the y-axis, :math:`\tau` is the time constant of the exponential decay fitted to the chi squared as a function of steps. The total steps and total runtime are used to convert its units to hours. As a general rule, increasing the number of steps and decreasing the number of walkers increases the total computation time but ensures convergence. 34 | Decreasing the number of steps and increasing the number of walkers reduces 35 | the computation time but risks a failure to converge. 36 | 37 | OpenHPC - Slurm 38 | --------------- 39 | Bjet_MCMC benefits greatly from running on multiple parallel CPUs, and takes 40 | hours to run. Users may opt to utilize a computing cluster to decrease runtime 41 | and free up their PC. Below is a script that can be used to submit Bjet_MCMC 42 | jobs to the Slurm batch scheduling system used on many compute clusters such 43 | as UCSC's Hummingbird. 44 | 45 | .. code-block:: console 46 | 47 | #!/bin/bash 48 | #SBATCH --job-name=bjet #Job Name 49 | #SBATCH --mail-type=ALL #What events you want emailed to you (ALL, BEGIN, END, REQUEUE, FAIL) 50 | #SBATCH --mail-user= #Email to send job status. Input your email into 51 | #SBATCH -p 128x24 #Name of which partition is being used 128x24 52 | #SBATCH --nodes=1 #Number of nodes requested 53 | #SBATCH --ntasks=1 #Number of tasks requested 54 | #SBATCH --cpus-per-task=24 #Number of CPUs requested. Make sure that cores requested here matches the amount of cores requested in the config file. 55 | #SBATCH --output=bjet_%j.out #Output log. When job runs, output will be written to this file. 56 | #SBATCH --error=bjet_%j.err #Error log. When job runs, error will be written to this file. 57 | #SBATCH --mem=10G #Amount of memory per node 58 | #SBATCH --time=5-00:00:00 #the job will be automatically terminated after 5 days if it is still running 59 | 60 | #Code to run Bjet 61 | module load miniconda3/3.12 # load miniconda on the node 62 | 63 | # init conda and activate the bjet-mcmc environment 64 | conda init 65 | conda activate bjet-mcmc 66 | 67 | # start Bjet_MCMC 68 | python3 /absolute/path/to/Bjet_MCMC/bjet_mcmc/blazar_run_mcmc.py 69 | 70 | 71 | -------------------------------------------------------------------------------- /docs/source/data_format.rst: -------------------------------------------------------------------------------- 1 | Data format 2 | =========== 3 | 4 | Data by default is assumed to be in data files with the following columns as labels in the first row:: 5 | 6 | !E(eV) F(ergcm-2s-1) delta_E(-) delta_E(+) delta_F(-) delta_F(+) instrument 7 | 8 | Upper limits (U.L.) and lower limits (L.L.) can be used. Upper(Lower) limits are considered in the fitting algorithm as likelihood step functions, with a flat probability of 95% below(above) the limit and 5% above(below), extending on both sides to infinity. 9 | The value set for ``F(ergcm-2s-1)`` should be the flux U.L.(L.L.) at 95% confidence level. 10 | 11 | Error format for U.L.: :: 12 | 13 | delta_F(-) delta_F(+) 14 | 0 0 15 | 16 | Error format for L.L.: :: 17 | 18 | delta_F(-) delta_F(+) 19 | -1 0 20 | 21 | 22 | Example of an SED data file 23 | --------------------------- 24 | 25 | This is the default data file, already available in Bjet_MCMC : ``real_data/J1010_SED_reduced.dat``. 26 | This dataset of the blazar 1RXS J101015.9-311909 comes from `Cerruti et al. (2013) `_ :: 27 | 28 | 29 | !E(eV) F(ergcm-2s-1) delta_E(-) delta_E(+) delta_F(-) delta_F(+) instrument 30 | 1.5548 8.48E-012 0.17621 0.16843 4.11E-013 4.11E-013 ATOM 31 | 1.9356 8.97E-012 0.16314 0.27997 2.03E-012 3.52E-012 ATOM 32 | 2.8327 1.05E-011 0.35125 0.43236 3.03E-012 5.25E-012 ATOM 33 | 2.2558 1.02E-011 0.18799 0.22558 2.87E-013 2.87E-013 Swift-UVOT 34 | 2.8198 8.63E-012 0.33838 0.44523 1.96E-013 1.96E-013 Swift-UVOT 35 | 3.5449 7.52E-012 0.44311 0.59081 1.83E-013 1.83E-013 Swift-UVOT 36 | 4.0023 9.83E-012 0.90052 1.6373 2.36E-013 2.36E-013 Swift-UVOT 37 | 5.1696 1.30E-011 0.73852 1.0339 6.32E-013 6.32E-013 Swift-UVOT 38 | 5.6396 1.10E-011 0.86763 1.2532 2.14E-013 2.14E-013 Swift-UVOT 39 | 395 9.65E-012 85 85 1.14E-012 1.14E-012 Swift-XRT 40 | 520 1.13E-011 40 40 1.42E-012 1.42E-012 Swift-XRT 41 | 625 7.70E-012 65 65 8.18E-013 8.18E-013 Swift-XRT 42 | 750 7.95E-012 60 60 7.81E-013 7.81E-013 Swift-XRT 43 | 855 7.92E-012 45 45 8.42E-013 8.42E-013 Swift-XRT 44 | 955 6.19E-012 55 55 6.44E-013 6.44E-013 Swift-XRT 45 | 1065 7.15E-012 55 55 7.01E-013 7.01E-013 Swift-XRT 46 | 1185 6.79E-012 65 65 6.37E-013 6.37E-013 Swift-XRT 47 | 1310 7.11E-012 60 60 7.02E-013 7.02E-013 Swift-XRT 48 | 1440 5.75E-012 70 70 6.10E-013 6.10E-013 Swift-XRT 49 | 1585 5.82E-012 75 75 6.36E-013 6.36E-013 Swift-XRT 50 | 1760 5.62E-012 100 100 6.04E-013 6.04E-013 Swift-XRT 51 | 2030 4.69E-012 170 170 5.15E-013 5.15E-013 Swift-XRT 52 | 2420 5.45E-012 220 220 6.26E-013 6.26E-013 Swift-XRT 53 | 3040 4.14E-012 400 400 4.87E-013 4.87E-013 Swift-XRT 54 | 4280 3.41E-012 840 840 4.10E-013 4.10E-013 Swift-XRT 55 | 5820 2.81E-012 700 700 6.79E-013 6.79E-013 Swift-XRT 56 | 1698600000 1.29E-012 698650000 1186800000 0.00E+000 0.00E+000 Fermi-LAT 57 | 4901300000 1.92E-012 2015900000 3424300000 5.59E-013 5.59E-013 Fermi-LAT 58 | 14142000000 1.43E-012 5816600000 9880400000 7.64E-013 7.64E-013 Fermi-LAT 59 | 40806000000 2.27E-012 16783000000 28509000000 1.41E-012 1.41E-012 Fermi-LAT 60 | 117740000000 9.22E-012 48426000000 82259000000 0.00E+000 0.00E+000 Fermi-LAT 61 | 296236003888.79 1.57E-012 88136003888.790 125463996111.20 4.25E-013 4.40E-013 H.E.S.S. 62 | 600355719552.99 5.25E-013 178655719552.99 254344280447.00 2.14E-013 2.22E-013 H.E.S.S. 63 | 1216727524961.9 2.22E-013 362027524961.93 515372475038.06 1.71E-013 1.81E-013 H.E.S.S. 64 | 2465769133556.5 4.30E-013 733669133556.50 1044430866443.5 1.75E-013 1.90E-013 H.E.S.S. 65 | -------------------------------------------------------------------------------- /bjet_core/README.md: -------------------------------------------------------------------------------- 1 | # Bjet mcmc 2 | 3 | This code is a slightly modified version of `bj02` by Olivier Hervet. 4 | Modified by Sarah Youngquist in February 2022, updated June 2022. 5 | 6 | ## Usage 7 | 8 | ### Calling the executable: 9 | - Usage 1: `bj_core --help` 10 | - Usage 2: `bj_core ` 11 | - Usage 3: `bj_core 0 `: same execution as usage 2, _prev files made 12 | - Usage 4: `bj_core 1 `: no _prev files made 13 | - Usage 5: `bj_core 2 `: _prev files made 14 | - Usage 6: `bj_core 3 `: no _prev files made 15 | - Usage 7: `bj_core 0/1 `: 16 | params from command line, 0 = yes _prev files, 1 = no 17 | - Usage 8: `bj_core 2/3 `: 18 | params from command line, 2 = yes _prev files, 3 = no 19 | 20 | #### Modes: 21 | - 0: _prev files are made, save in default data folder 22 | - 1: no _prev files are made, save in default data folder 23 | - 2: _prev files are made, save in specified data folder 24 | - 3: no _prev files are, save in specified data folder 25 | 26 | #### Valid values for model type: 27 | - 0: model with just blob 28 | - 1: blob + EIC parameters 29 | - Other models not yet implemented 30 | 31 | (default data directory is in the same directory as the executable, named "data") 32 | 33 | 34 | ### Order of parameters in command line: 35 | 36 | #### Model type 0: 37 | After `bj_core <0, 1, 2, 3> 0`: 38 | 39 | `z, H_0, THETA, DOP_B, K1, N1, N2, GAMMA_MIN, GAMMA_MAX, GAMMA_BRK, B, R_src, 40 | L_src, IIR_level, D_b, NU_DIM, NU_STR, NU_END, prefix` 41 | 42 | argc should be 22 or 23 depending on if data folder is listed 43 | 44 | #### Model type 1: 45 | After `bj_core <0, 1, 2, 3> 1`: 46 | 47 | `z, H_0, THETA, DOP_B, K1, N1, N2, GAMMA_MIN, GAMMA_MAX, GAMMA_BRK, B, R_src, 48 | L_src, IIR_level, D_b, T_BB, TBB_tor, L_nuc, tau, L_tor, tau, NU_DIM, NU_STR, NU_END, prefix` 49 | 50 | *Note that tau is present twice, this is a slight error in the bjet code. The second tau value is not used for 51 | anything, but it must be inputted. 52 | 53 | argc should be 28 or 29 depending on if data folder is listed 54 | 55 | #### Example: 56 | 57 | ``` 58 | ./bj_core 3 /Users/sed_calculations 1 0.34 69.6 0.57 50.0 612.1 2.28 3.74 2816.9 1803000 44806 0.00236 5.94e+17 0 1 3.8e+15 2013 2.0e+4 1.7e+21 1.5e-10 5.5e+20 9.0e-5 99 50000000.0 1e+29 run 59 | ``` 60 | 61 | ^ here, the 3 indicates that the data folder is specified and no prev file is made. 1 is the EIC model type. Then 0.34 is z (redshift) and then the rest of the parameters are enumerated. 62 | 63 | ## Changes 64 | Changes to the code by Sarah Youngquist in Feb 2022: 65 | 66 | - Allow for _prev files not to be created. 67 | Specified in the command line with the mode. 68 | Stored in INPUT_MODE 69 | Now, any time \_prev\_*.dat file would be made, it is conditional on INPUT_MODE being 0 (user entered 0 or 2 for mode) 70 | - Allow for specifying the data folder 71 | This is specified in the command line with the mode. 72 | Note: relative path to any data file 73 | - Use the model without a parameter file, inputting parameters from the 74 | command line. 75 | - Function load_params_from_list(argv, model_type, index, argc) added. 76 | - Most of main method moved into run_models 77 | - In main method, parse the input mode and set the input type, set data directory 78 | if applicable, parse model type if applicable, call either load_params or load_params_from_list 79 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | share/python-wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | MANIFEST 28 | 29 | # PyInstaller 30 | # Usually these files are written by a python script from a template 31 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 32 | *.manifest 33 | *.spec 34 | 35 | # Installer logs 36 | pip-log.txt 37 | pip-delete-this-directory.txt 38 | 39 | # Unit test / coverage reports 40 | htmlcov/ 41 | .tox/ 42 | .nox/ 43 | .coverage 44 | .coverage.* 45 | .cache 46 | nosetests.xml 47 | coverage.xml 48 | *.cover 49 | *.py,cover 50 | .hypothesis/ 51 | .pytest_cache/ 52 | cover/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | .pybuilder/ 76 | target/ 77 | 78 | # Jupyter Notebook 79 | .ipynb_checkpoints 80 | 81 | # IPython 82 | profile_default/ 83 | ipython_config.py 84 | 85 | # pyenv 86 | # For a library or package, you might want to ignore these files since the code is 87 | # intended to run in multiple environments; otherwise, check them in: 88 | # .python-version 89 | 90 | # pipenv 91 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 92 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 93 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 94 | # install all needed dependencies. 95 | #Pipfile.lock 96 | 97 | # poetry 98 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. 99 | # This is especially recommended for binary packages to ensure reproducibility, and is more 100 | # commonly ignored for libraries. 101 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control 102 | #poetry.lock 103 | 104 | # pdm 105 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. 106 | #pdm.lock 107 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it 108 | # in version control. 109 | # https://pdm.fming.dev/latest/usage/project/#working-with-version-control 110 | .pdm.toml 111 | .pdm-python 112 | .pdm-build/ 113 | 114 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm 115 | __pypackages__/ 116 | 117 | # Celery stuff 118 | celerybeat-schedule 119 | celerybeat.pid 120 | 121 | # SageMath parsed files 122 | *.sage.py 123 | 124 | # Environments 125 | .env 126 | .venv 127 | env/ 128 | venv/ 129 | ENV/ 130 | env.bak/ 131 | venv.bak/ 132 | 133 | # Spyder project settings 134 | .spyderproject 135 | .spyproject 136 | 137 | # Rope project settings 138 | .ropeproject 139 | 140 | # mkdocs documentation 141 | /site 142 | 143 | # mypy 144 | .mypy_cache/ 145 | .dmypy.json 146 | dmypy.json 147 | 148 | # Pyre type checker 149 | .pyre/ 150 | 151 | # pytype static type analyzer 152 | .pytype/ 153 | 154 | # Cython debug symbols 155 | cython_debug/ 156 | 157 | # PyCharm 158 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can 159 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore 160 | # and can be added to the global gitignore or merged into this file. For a more nuclear 161 | # option (not recommended) you can uncomment the following to ignore the entire idea folder. 162 | #.idea/ 163 | 164 | -------------------------------------------------------------------------------- /docs/source/outputs.rst: -------------------------------------------------------------------------------- 1 | Outputs 2 | ======= 3 | .. _outputs: 4 | 5 | By default, all outputs are written to a folder in ``local_results/`` entitled ``folder_label_yyyy-mm-dd-hh:mm:ss`` 6 | 7 | ``backend.h5`` 8 | -------------- 9 | H5 file containing the entire chain from the MCMC and the corresponding log-likelihood values. This is updated continuously. If the code crashes, all existing results are still present. H5 files can be re-loaded as the current state for the MCMC at the beginning of another run (see the main method in ``blazar_run_mcmc.py``) or loaded to use for statistics or plotting (see ``load_backend()`` in ``blazar_report.py``). 10 | 11 | Text files 12 | ---------- 13 | 14 | - ``basic_info.txt`` 15 | 16 | Contains information from the configurations file, some paths and the running time. 17 | e.g. :: 18 | 19 | folder name: local_results/J1010_2023-07-04-23:03:45 20 | report description: J1010 21 | 22 | config file: mcmc_config.txt 23 | prev_files: False, use_param_file: False 24 | 25 | configurations: 26 | {'description': 'J1010', 'folder_label': 'J1010', 'eic': False, 'data_file': 'real_data/J1010_SED_reduced.dat', 'n_steps': 5000, 'n_walkers': 100, 'discard': 200, 'parallel': True, 'cores': 15, 'use_variability': True, 'tau_variability': 24.0, 'redshift': 0.143, 'custom_alpha2_limits': False, 'bb_temp': 'null', 'l_nuc': 'null', 'tau': 'null', 'blob_dist': 'null', 'alpha2_limits': [1.5, 7.5], 'fixed_params': [-inf, -inf, -inf, -inf, -inf, -inf, -inf, -inf, -inf]} 27 | 28 | p0: random 29 | 30 | time: 5:45:22.151980 31 | 32 | - ``info.txt`` 33 | 34 | Main output containing the best fit parameters with associated errors, and statistical information. 35 | e.g. :: 36 | 37 | configurations: 38 | {'description': 'J1010_quicktest', 'folder_label': 'J1010', 'eic': False, 'data_file': 'real_data/J1010_SED_reduced.dat', 'n_steps': 100, 'n_walkers': 50, 'discard': 20, 'parallel': True, 'cores': 15, 'use_variability': True, 'tau_variability': 24.0, 'redshift': 0.143, 'custom_alpha2_limits': False, 'bb_temp': 'null', 'l_nuc': 'null', 'tau': 'null', 'blob_dist': 'null', 'alpha2_limits': [1.5, 7.5], 'fixed_params': [83.8, -inf, -inf, -inf, -inf, -inf, -inf, -inf, -inf]} 39 | 40 | Parameter Best Value 1sigma Range 41 | K 2.98e+04 2.98e+04 - 2.98e+04 42 | alpha_1 2.90e+00 2.90e+00 - 2.90e+00 43 | alpha_2 5.84e+00 5.84e+00 - 5.84e+00 44 | gamma_min 5.29e+02 5.29e+02 - 5.29e+02 45 | gamma_max 3.56e+06 3.56e+06 - 3.56e+06 46 | gamma_break 2.09e+05 2.09e+05 - 2.09e+05 47 | B 2.08e-02 2.08e-02 - 2.08e-02 48 | R 5.05e+16 5.05e+16 - 5.05e+16 49 | Reduced chi squared: 279.39 / 26 = 10.75 50 | 51 | 52 | best params: [ 4.4744869 2.90451014 5.83862833 2.72311678 6.55186859 5.32035444 53 | -1.68218932 16.70306255], chi squared = 279.38725352463666 54 | 55 | min_1sigma_params: [ 4.4744869 2.90451014 5.83862833 2.72311678 6.55186859 5.32035444 56 | -1.68218932 16.70306255] 57 | max_1sigma_params: [ 4.4744869 2.90451014 5.83862833 2.72311678 6.55186859 5.32035444 58 | -1.68218932 16.70306255] 59 | 60 | autocorrelation time: avg = 8.403521463690534 steps 61 | 62 | - ``bjet.log`` 63 | 64 | Log file of the standard terminal output of bjet. It contains physical information from the best model fitted to the data. 65 | 66 | 67 | Science plots 68 | ------------- 69 | 70 | - ``model_and_data.svg`` 71 | 72 | Multiwavelength SED with data points, best model, and 1-sigma confidence level contours of the best model. Note the 1-sigma contours on this plot are an approximation of the real contours to save computation time. 73 | e.g. 74 | 75 | .. image:: ../figures/model_and_data.png 76 | :width: 400 77 | 78 | - ``particle_spectrum.svg`` 79 | 80 | Particle spectrum with 1-sigma confidence level contours of the best model. 81 | e.g. 82 | 83 | .. image:: ../figures/particle_spectrum.png 84 | :width: 400 85 | 86 | - ``cooling_time_obs(Thomson).svg`` 87 | 88 | Particle cooling time in the observer's frame considering the Thomson regime. 89 | 90 | .. math:: \tau_\mathrm{cool}(\gamma) = \frac{3 m_e c}{4 (U_B + U'_\mathrm{rad}) \sigma_T \gamma} \frac{1+z}{\delta} 91 | 92 | With :math:`U_\mathrm{B}` the magnetic field energy density and :math:`U'_\mathrm{rad}` the sum of all soft photons radiation field densities in the blob's frame. 93 | e.g. 94 | 95 | .. image:: ../figures/cooling_time_obs(Thomson).png 96 | :width: 400 97 | 98 | :math:`\chi^2` plots 99 | -------------------- 100 | :math:`\chi^2` plots are critical to assess the convergence of the MCMC chain. They provide insights to the user in taking longer/shorter chains or changing the number of free parameters. 101 | 102 | - ``chi_squared_plot_all.jpeg`` 103 | 104 | :math:`\chi^2` of all individual walkers. 105 | e.g. 106 | 107 | .. image:: ../figures/chi_squared_plot_all.jpeg 108 | :width: 400 109 | 110 | - ``chi_squared_plot_best.svg`` 111 | 112 | Best :math:`\chi^2` at each step. 113 | e.g. 114 | 115 | .. image:: ../figures/chi_squared_plot_best.png 116 | :width: 400 117 | 118 | - ``chi_squared_plot_med.svg`` 119 | 120 | Median of all walker's :math:`\chi^2` at each step. Fitted with exponential decay function. 121 | e.g. 122 | 123 | .. image:: ../figures/chi_squared_plot_med.png 124 | :width: 400 125 | 126 | Corner plot 127 | ----------- 128 | 1D posterior probability distribution of each free parameter, 2D posterior probability distribution of each pair of parameters, best parameter, 1-sigma parameter range. 129 | e.g. 130 | 131 | .. image:: ../figures/corner_plot.png 132 | :width: 800 133 | -------------------------------------------------------------------------------- /bjet_mcmc/blazar_initialize.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | """ 4 | file name: blazar_initialize.py 5 | 6 | Purpose: Implement functions to make necessary directories and compile the c++ code 7 | 8 | """ 9 | import os 10 | import shutil 11 | import subprocess 12 | 13 | from bjet_mcmc.blazar_properties import * 14 | 15 | __all__ = ["make_dirs", "compile_bjet", "initialize"] 16 | 17 | 18 | def make_dirs( 19 | data_folder=None, results_folder=None, parameter_folder=None, parameter_file=False 20 | ): 21 | """ 22 | This function, `make_dirs`, creates folders based on the input parameters. 23 | 24 | The function first checks if any of the input folder parameters are None. If they are, it assigns default values based on predefined constants. 25 | 26 | Then, it iterates through each of the folders (data_folder, results_folder, parameter_folder) and checks if they are not None. If they are not None, it checks if the folder path does not already exist. If it doesn't exist, it creates the folder. 27 | 28 | Finally, it checks if the current folder being processed is the results_folder and if the folder path doesn't already exist. If it doesn't exist, it creates the folder under a specific path. 29 | 30 | Note: This function relies on the presence of certain constants (e.g. DATA_FOLDER, RESULTS_FOLDER, PARAMETER_FOLDER, BASE_PATH, FOLDER_PATH), but these constants are not defined or included in this documentation. 31 | 32 | Example usage: 33 | make_dirs(data_folder='data', results_folder='results', parameter_folder='parameters', parameter_file=True) 34 | 35 | :param data_folder: The folder to store data files. Defaults to DATA_FOLDER. 36 | :type data_folder: str 37 | :param results_folder: The folder to store results files. Defaults to RESULTS_FOLDER. 38 | :type results_folder: str 39 | :param parameter_folder: The folder to store parameter files. If None and parameter_file is True, it defaults to the value of PARAMETER_FOLDER. If None and parameter_file is False, the parameter folder will not be created. 40 | :type parameter_folder: str 41 | :param parameter_file: A boolean indicating whether a parameter file is present or not. Defaults to False. 42 | :type parameter_file: bool 43 | :return: None 44 | :rtype: None 45 | 46 | 47 | """ 48 | if data_folder is None: 49 | data_folder = DATA_FOLDER 50 | if results_folder is None: 51 | results_folder = RESULTS_FOLDER 52 | if not parameter_file: 53 | parameter_folder = None # no parameter files --> don't make folder 54 | elif parameter_folder is None: 55 | parameter_folder = PARAMETER_FOLDER 56 | for folder in (data_folder, results_folder, parameter_folder): 57 | if folder is not None: 58 | if not os.path.exists(BASE_PATH + folder): 59 | os.mkdir(BASE_PATH + folder) 60 | if folder == results_folder and not os.path.exists(FOLDER_PATH + folder): 61 | os.mkdir( 62 | FOLDER_PATH + folder 63 | ) # want results directory in both tmp and main if tmp 64 | 65 | 66 | def compile_bjet(bjet_folder=None, executable=None, verbose=False): 67 | """ 68 | Compiles the specified BJET folder using the specified executable. 69 | 70 | :param bjet_folder: The folder containing the BJET files to be compiled. If not provided, the default CPP_FOLDER will be used. 71 | :type bjet_folder: str 72 | :param executable: The name of the executable file to be generated. If not provided, the default EXECUTABLE will be used. 73 | :type executable: str 74 | :param verbose: If True, the make process will display verbose output. If False, the output will be suppressed. Default is False. 75 | :type verbose: bool 76 | :return: None 77 | :rtype: None 78 | """ 79 | if bjet_folder is None: 80 | bjet_folder = CPP_FOLDER 81 | if executable is None: 82 | executable = EXECUTABLE 83 | 84 | os.chdir(FOLDER_PATH + bjet_folder) 85 | files = [f for f in os.listdir() if f.endswith(".o")] 86 | for f in files: 87 | os.remove(f) 88 | if os.path.exists(executable): 89 | os.remove(executable) 90 | if verbose: 91 | subprocess.run("make", executable) 92 | else: 93 | subprocess.run( 94 | "make", stderr=open(os.devnull, "wb"), stdout=open(os.devnull, "wb") 95 | ) 96 | 97 | 98 | def initialize( 99 | data_folder=None, 100 | results_folder=None, 101 | parameter_folder=None, 102 | parameter_file=False, 103 | bjet_folder=None, 104 | executable=None, 105 | run_compile=True, 106 | ): 107 | """ 108 | Initializes the software by creating necessary directories, compiling the required files, and copying the executable. 109 | 110 | :param data_folder: The path to the data folder. Defaults to None. 111 | :type data_folder: str 112 | :param results_folder: The path to the results folder. Defaults to None. 113 | :type results_folder: str 114 | :param parameter_folder: The path to the parameter folder. Defaults to None. 115 | :type parameter_folder: str 116 | :param parameter_file: Indicates whether a parameter file is present. Defaults to False. 117 | :type parameter_file: bool 118 | :param bjet_folder: The path to the bjet folder. Defaults to None. 119 | :type bjet_folder: str 120 | :param executable: The name of the executable file. Defaults to None. 121 | :type executable: str 122 | :param run_compile: Indicates whether to compile the bjet executable. Defaults to True. 123 | :type run_compile: bool 124 | :return: None 125 | :rtype: None 126 | """ 127 | make_dirs( 128 | data_folder=data_folder, 129 | results_folder=results_folder, 130 | parameter_folder=parameter_folder, 131 | parameter_file=parameter_file, 132 | ) 133 | if run_compile: 134 | compile_bjet(bjet_folder=bjet_folder, executable=executable) 135 | if TMP: 136 | if not os.path.exists(BASE_PATH + bjet_folder): 137 | os.mkdir(BASE_PATH + bjet_folder) 138 | shutil.copy( 139 | FOLDER_PATH + bjet_folder + "/" + executable, 140 | BASE_PATH + bjet_folder + "/" + executable, 141 | ) 142 | 143 | 144 | if __name__ == "__main__": 145 | initialize() 146 | -------------------------------------------------------------------------------- /bjet_core/bj_core.h: -------------------------------------------------------------------------------- 1 | /* 2 | Slightly modified version of bj02.h for use in MCMC code; modified by Sarah Youngquist in Feb 2022 3 | See bj_core.cpp for an explanation of the changes. 4 | */ 5 | /** @file */ 6 | 7 | #ifndef BLAZARS_MCMC_BJ02_COPY_H 8 | #define BLAZARS_MCMC_BJ02_COPY_H 9 | 10 | 11 | using namespace std; 12 | 13 | #include 14 | 15 | namespace bj_core02 { 16 | 17 | 18 | 19 | // FLAGS 20 | const int PRINT = 0; //!< 1=True, 0=False 21 | const int DEBUG = 0; //!< 1=True, 0=False 22 | //#warning "DEUBG flag enabled" 23 | 24 | // PHYSICAL CONSTANTS c.g.i. 25 | 26 | const double q0 = 0.5; 27 | const double pc = 3.086 * 1.0e+18; //!< [cm] 28 | const double H0SI = 70.; //!< SI: km/s/Mpc 29 | const double H0 = H0SI*1.e5/(1.e6*pc);//!< cgs: s-1 30 | const double sig_T = 6.652453 * 1.0e-25; //!< [cm^2] 31 | const double m_e = 9.109558 * 1.0e-28; //!< [g] 32 | const double c = 2.997924 * 1.0e+10; //!< [cm / s] 33 | const double h = 6.626296 * 1.0e-27; //!< [erg * s] 34 | const double sig = 5.66961 * 1.0e-05; //!< [erg / (s * cm^2 * K^4)] 35 | const double m_p = 1.672623 * 1.0e-24; //!< [g] 36 | const double e = 4.803250 * 1.0e-10; //!< [esu] 37 | const double keV = 2.417965 * 1.0e+17; //!< [Hz] 38 | const double G = 6.6726 * 1.0e-08; //!< [dyn / (g^2 * cm^2)] 39 | const double k_B = 1.380622 * 1.0e-16; //!< [erg / K] 40 | const double M_sol = 1.989 * 1.0e+33; //!< [g] 41 | const double eV_K = 11.6048 * 1.0e+3; //!< [K] 42 | const double hour = 3600.0; //!< [s] 43 | const double day = 24.0 * hour; //!< [s] 44 | 45 | 46 | // PHYSICAL CONSTANTS S.I. 47 | 48 | const double PLANCK = 6.6260693e-34; //!< J.s 49 | const double eV = 1.602e-19; //!< J 50 | const double PARSEC = pc; //!< cm 51 | const double ERG = 1.e-7; //!< J 52 | const double MELEC = 0.511e6; //!< eV 53 | const double HZ_PER_EV = 2.145e14; 54 | const double LIGHTSPEED = c; //!< cm/s 55 | const double SIGMAT = sig_T; //!`_. This is the physical core of Bjet_MCMC and can be run in standalone mode outside the MCMC frame. 5 | 6 | run_Bjet_manual.py 7 | ------------------- 8 | If you want to run Bjet manually in its variant forms (pure SSC, SSC+EIC, multi-zone SSC+EIC), it is advised to use the Python script ``run_Bjet_manual.py``. This script launches ``bjet_core`` with a given parameter file and plots the resulting SED (data + model). 9 | Users can freely edit this script for their needs. This is especially useful for quick fit-by-eye processes, or to visualize the impact of parameters on the SED. 10 | 11 | You can adapt lines 40-60 with your chosen setup and inputs. You will need to call a parameter file, following the format of the example given in ``parameter_files/J1010.par``. The SED data file format is the same as for the general use of BJet_MCMC, with an example given in ``real_data/J1010_SED_reduced.dat`` 12 | 13 | 14 | Parameter file 15 | ------------------- 16 | Example of ``parameter_files/J1010.par``: :: 17 | 18 | ------------------------------------------------------------------------------ 19 | Transformation_parameters 20 | ------------------------------------------------------------------------------ 21 | 0.143 redshift 22 | 69.6 Hubble_constant______________________________________[km/(sMpc)] 23 | 0.57 angle_to_the_line_of_sight___________________________[degrees] 24 | ------------------------------------------------------------------------------ 25 | Blob_parameters 26 | ------------------------------------------------------------------------------ 27 | 8.38e+01 Doppler_factor 28 | 4.24e+03 Particle_density_____________________________________[1/cm^3] 29 | 2.56 First_slope_of_particle_energy_spectrum 30 | 3.75 Second_slope_of_particle_energy_spectrum 31 | 9.22 Minimum_electrons_energy 32 | 1.99e+06 Maximum_electrons_energy 33 | 2.13e+05 Break_in_electrons_energy_spectrum 34 | 1.71e-03 Magnetic_field_______________________________________[G] 35 | 1.40e+17 Radius_of_emitting_region____________________________[cm] 36 | 0 length_of_emitting_region_(0_for_spherical_geometry)_[cm] 37 | 1 absorption_by_EBL_(0=NO___1=YES) 38 | 9.0e+17 distance_blob_SMBH_(host_galaxy_frame)_______________[cm] 39 | ------------------------------------------------------------------------------ 40 | Extern_Inverse_Compton_parameter 41 | ------------------------------------------------------------------------------ 42 | 0 compute_EIC_(0=NO___1=YES) 43 | 0 compute_X_corona_(0=NO___1=YES) 44 | 4.0e+4 Disk_black_body_temperature__________________________[K] 45 | 2.0e+4 Torus_black_body_temperature_________________________[K] 46 | 3.0e+43 Luminosity_of_the_disk_______________________________[erg/s] 47 | 9.0e-5 Tau___fraction_of_L_disk_reprocessed_isotropically 48 | 5.5e+20 Luminosity_of_the_torus______________________________[erg/s] 49 | 9.0e-5 Tau___fraction_of_L_tor_reprocessed_isotropically 50 | ------------------------------------------------------------------------------ 51 | Jet_parameters 52 | ------------------------------------------------------------------------------ 53 | 0 compute_JET_(0=NO___1=YES) 54 | 3.0 Doppler_factor 55 | 1.0e+2 Initial_particle_density_____________________________[1/cm^3] 56 | 2.1 Slope_of_particle_energy_spectrum 57 | 1.0e+3 Minimum_electrons_energy 58 | 2.0e+4 Maximum_electrons_energy 59 | 0.08 Initial_magnetic_field_______________________________[G] 60 | 1.2e+17 Inner_radius_(host_galaxy_frame)_____________________[cm] 61 | 300 Jet_length_(host_galaxy_frame)_______________________[pc] 62 | 1.0 Half-opening_angle_of_jet_(host_galaxy_frame)________[deg] 63 | 50 number_of_slices 64 | ------------------------------------------------------------------------------ 65 | Numerical_parameters 66 | ------------------------------------------------------------------------------ 67 | 99 number_of_spectral_points 68 | 50000000.0 minimal_frequency____________________________________[Hz] 69 | 1e+29 maximal_frequency____________________________________[Hz] 70 | test_bj prefix_of_file_names 71 | 72 | **Some instructions for using a parameter file:** 73 | 74 | - Do not remove/add lines, do not change the order of parameters, this will crash the code. 75 | - You can activate/deactivate thermal EIC with the option ``compute_EIC_(0=NO___1=YES)`` and the extended SSC jet with ``compute_JET_(0=NO___1=YES)``. 76 | - The torus and X-ray corona parameters are unsafe to use. 77 | - I suggest not editing the Numerical_parameters, but you can increase the number of spectral points up to 200 if you want a smoother SED model (it will also take more time to compute). 78 | 79 | 80 | 81 | 82 | Manual installation of bjet_core 83 | ------------------- 84 | The following parts are for more advanced users who want to use the C++ code ``bjet_core`` directly. 85 | 86 | The code is in the ``bjet_core`` folder. The necessary files are ``bj_core.cpp``, ``bj_core.h``, ``processes_supp_core.cpp``, and ``processes_supp_core.h``. 87 | 88 | Compile the executable with 89 | 90 | .. code-block:: console 91 | 92 | $ make bj_core 93 | 94 | Usage 95 | ----- 96 | 97 | Options for calling the executable: 98 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 99 | 100 | - Usage 1: ``bj_core --help`` 101 | - Usage 2: ``bj_core `` 102 | - Usage 3: ``bj_core 0 `` same execution as usage 2, ``_prev files`` made 103 | - Usage 4: ``bj_core 1 `` no _prev files made 104 | - Usage 5: ``bj_core 2 `` _prev files made 105 | - Usage 6: ``bj_core 3 `` no _prev files made 106 | - Usage 7: ``bj_core 0/1 ``, 0 = yes ``_prev files``, 1 = no 107 | - Usage 8: ``bj_core 2/3 ``, 2 = yes ``_prev files``, 3 = no 108 | 109 | Parameter files 110 | ^^^^^^^^^^^^^^^ 111 | 112 | Parameter files specified in the command line should be paths relative to the ``bj_core`` executable. See ``params.txt`` in ``bjet_core`` for an example parameter file. 113 | 114 | 115 | Modes: 116 | ^^^^^^ 117 | 118 | A `_prev`` file is a file with the previous model SED. When this option is activated, the model will not erase the SED from the former execution of the code. This is especially useful when doing "fit-by-eye"> to see the effects of a change in the model parameters on the same SED plot. 119 | - 0: ``_prev`` files are made, save in default data folder 120 | - 1: no ``_prev`` files are made, save in default data folder 121 | - 2: ``_prev`` files are made, save in specified data folder 122 | - 3: no ``_prev`` files are made, save in specified data folder 123 | 124 | (The default data directory is in the same directory as the executable, named "data") 125 | 126 | Valid values for model type: 127 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 128 | 129 | - 0: model with just blob 130 | - 1: blob + EIC parameters 131 | - Other models not yet implemented. The full multi-zone model can be used only with a parameter file. 132 | 133 | Order of parameters in command line: 134 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 135 | 136 | - Model type 0: 137 | 138 | .. code-block:: console 139 | 140 | $ bj_core <0, 1, 2, 3> 0 (model type) z, H_0, THETA, DOP_B, K1, N1, N2, GAMMA_MIN, GAMMA_MAX, GAMMA_BRK, B, R_src, L_src, IIR_level, D_b, NU_DIM, NU_STR, NU_END, prefix 141 | 142 | argc should be 22 or 23 depending on if data folder is listed 143 | 144 | - Model type 1 [*]_: 145 | 146 | .. code-block:: console 147 | 148 | $ bj_core <0, 1, 2, 3> 1 (model type) z, H_0, THETA, DOP_B, K1, N1, N2, GAMMA_MIN, GAMMA_MAX, GAMMA_BRK, B, R_src, L_src, IIR_level, D_b, T_BB, TBB_tor, L_nuc, tau, L_tor, tau, NU_DIM, NU_STR, NU_END, prefix 149 | 150 | .. [*] Note that tau is present twice, this is a slight error in the bjet code. The second tau value is not used for anything, but it must be inputted. 151 | 152 | argc should be 28 or 29 depending on if data folder is listed 153 | 154 | - Example: 155 | 156 | .. code-block:: console 157 | 158 | $ ./bj_core 3 /Users/sed_calculations 1 0.34 69.6 0.57 50.0 612.1 2.28 3.74 2816.9 1803000 44806 0.00236 5.94e+17 0 1 3.8e+15 2013 2.0e+4 1.7e+21 1.5e-10 5.5e+20 9.0e-5 99 50000000.0 1e+29 run 159 | 160 | The 3 indicates that the data folder is specified and no prev file is made. 1 is the EIC model type. Then 0.34 is z (redshift) and the rest of the parameters are enumerated. 161 | -------------------------------------------------------------------------------- /bjet_mcmc/blazar_properties.py: -------------------------------------------------------------------------------- 1 | """ 2 | This gets the path to .../blazars-mcmc, which then allows for function calls 3 | to use the absolute path. 4 | """ 5 | 6 | import os 7 | 8 | # import pathlib 9 | import tempfile 10 | import numpy as np 11 | 12 | __all__ = [ 13 | "TMP", 14 | "INITIALIZE", 15 | "MAIN_FOLDER", 16 | "DATA_FOLDER", 17 | "RESULTS_FOLDER", 18 | "PARAMETER_FOLDER", 19 | "CPP_FOLDER", 20 | "EXECUTABLE", 21 | "TEMP_DIR", 22 | "BASE_PATH", 23 | "FOLDER_PATH", 24 | "NAME_STEM", 25 | "BlazarProperties", 26 | "modelProperties", 27 | "_get_path", 28 | "EIC_NUM_DIM", 29 | "EIC_PARAM_NAMES", 30 | "EIC_FORMATTED_PARAM_NAMES", 31 | "EIC_DETAILED_PARAM_NAMES", 32 | "EIC_PARAM_IS_LOG", 33 | "SSC_NUM_DIM", 34 | "SSC_PARAM_NAMES", 35 | "SSC_FORMATTED_PARAM_NAMES", 36 | "SSC_DETAILED_PARAM_NAMES", 37 | "SSC_PARAM_IS_LOG", 38 | ] 39 | 40 | PROGRAM_NAME = "/Bjet_MCMC" 41 | TMP = False 42 | INITIALIZE = False 43 | MAIN_FOLDER = "bjet_mcmc" 44 | DATA_FOLDER = "sed_calculations" 45 | RESULTS_FOLDER = "local_results" 46 | PARAMETER_FOLDER = "parameter_files" 47 | CPP_FOLDER = "bjet_core" 48 | EXECUTABLE = "bj_core" 49 | NAME_STEM = "run" 50 | 51 | 52 | class BlazarProperties(object): 53 | """ 54 | Module: BlazarProperties 55 | 56 | This module contains the definition of the BlazarProperties class, which is used to store properties related to blazar objects. 57 | 58 | Classes: 59 | BlazarProperties: A class used to store properties related to blazar objects. 60 | 61 | """ 62 | 63 | def __init__( 64 | self, 65 | num_dim, 66 | param_names, 67 | formatted_param_names, 68 | detailed_param_names, 69 | param_is_log, 70 | ): 71 | """ 72 | Class representing Blazar Properties. 73 | 74 | :param num_dim: number of dimensions 75 | :type num_dim: int 76 | :param param_names: list of parameter names 77 | :type param_names: list[str] 78 | :param formatted_param_names: list of formatted parameter names 79 | :type formatted_param_names: list[str] 80 | :param detailed_param_names: list of detailed parameter names 81 | :type detailed_param_names: list[str] 82 | :param param_is_log: list indicating whether parameters are logarithmic 83 | :type param_is_log: list[bool] 84 | 85 | :raises Exception: if dimensions of arrays conflict in blazar_properties 86 | """ 87 | self.NUM_DIM = num_dim 88 | self.PARAM_NAMES = param_names 89 | self.FORMATTED_PARAM_NAMES = formatted_param_names 90 | self.DETAILED_PARAM_NAMES = detailed_param_names 91 | self.PARAM_IS_LOG = param_is_log 92 | if ( 93 | not self.NUM_DIM 94 | == len(self.PARAM_NAMES) 95 | == len(self.FORMATTED_PARAM_NAMES) 96 | == len(self.DETAILED_PARAM_NAMES) 97 | == len(self.PARAM_IS_LOG) 98 | ): 99 | raise Exception("Dimensions of arrays conflict in blazar_properties.") 100 | 101 | 102 | def modelProperties(is_eic=False, fixed_params=None): 103 | """ 104 | :param is_eic: a boolean indicating whether the properties are for the EIC model (default is False) 105 | :type is_eic: bool 106 | :param fixed_params: a list of fixed parameter values to remove from the properties (default is None) 107 | :type fixed_params: list or None 108 | :return: the properties object with specified modifications 109 | :rtype: BlazarProperties 110 | """ 111 | sscProperties = BlazarProperties( 112 | 9, 113 | ["delta", "K", "n_1", "n_2", "gamma_min", "gamma_max", "gamma_break", "B", "R"], 114 | [ 115 | r"$\delta$", 116 | r"log $K$", 117 | r"$n_1$", 118 | r"$n_2$", 119 | r"log $\gamma_{min}$", 120 | r"log $\gamma_{max}$", 121 | r"log $\gamma_{break}$", 122 | r"log $B$", 123 | r"log $R$", 124 | ], 125 | [ 126 | "doppler factor (delta)", 127 | "log K [cm^-3]", 128 | "alpha 1", 129 | "alpha 2", 130 | "log gamma_min", 131 | "log gamma_max", 132 | "log gamma_break", 133 | "log B", 134 | "log R [cm]", 135 | ], 136 | [False, True, False, False, True, True, True, True, True], 137 | ) 138 | 139 | eicProperties = BlazarProperties( 140 | 13, 141 | [ 142 | "delta", 143 | "K", 144 | "n_1", 145 | "n_2", 146 | "gamma_min", 147 | "gamma_max", 148 | "gamma_break", 149 | "B", 150 | "R", 151 | "bb_temp", 152 | "l_nuc", 153 | "tau", 154 | "blob_dist", 155 | ], 156 | [ 157 | r"$\delta$", 158 | r"log $K$", 159 | r"$n_1$", 160 | r"$n_2$", 161 | r"log $\gamma_{min}$", 162 | r"log $\gamma_{max}$", 163 | r"log $\gamma_{break}$", 164 | r"log $B$", 165 | r"log $R$", 166 | r"log $T_{BB}$", 167 | r"log $L_{nuc}$", 168 | r"log $\tau$", 169 | r"log $D_{b}$", 170 | ], 171 | [ 172 | "doppler factor (delta)", 173 | "log K [cm^-3]", 174 | "alpha 1", 175 | "alpha 2", 176 | "log gamma_min", 177 | "log gamma_max", 178 | "log gamma_break", 179 | "log B", 180 | "log R [cm]", 181 | "log bb_temp", 182 | "log l_nuc", 183 | "log tau", 184 | "log blob_dist", 185 | ], 186 | [ 187 | False, 188 | True, 189 | False, 190 | False, 191 | True, 192 | True, 193 | True, 194 | True, 195 | True, 196 | True, 197 | True, 198 | True, 199 | True, 200 | ], 201 | ) 202 | 203 | if is_eic: 204 | parameters = eicProperties 205 | else: 206 | parameters = sscProperties 207 | # remove any frozen parameter from the parameter list 208 | if fixed_params: 209 | fixed_params2 = fixed_params.copy() 210 | i = 0 211 | while i < len(fixed_params2): 212 | if fixed_params2[i] != -np.inf: 213 | parameters.NUM_DIM -= 1 214 | del parameters.PARAM_NAMES[i] 215 | del parameters.FORMATTED_PARAM_NAMES[i] 216 | del parameters.DETAILED_PARAM_NAMES[i] 217 | del parameters.PARAM_IS_LOG[i] 218 | del fixed_params2[i] 219 | else: 220 | i += 1 221 | return parameters 222 | 223 | 224 | # TODO Implement a different scheme for saving output files. Do not place in program install location but in a user 225 | # defined analysis directory. 226 | def _get_path(): 227 | """ 228 | This function retrieves the base path of the current file and returns the path up to the main folder. 229 | 230 | .. note:: This method should return __file__ from the location of the Bjet-MCMC repository root, and not the python install location in `site-packages`. 231 | 232 | :return: The base path up to the main folder. 233 | :rtype: str 234 | """ 235 | base_path = str(os.path.dirname(__file__)) 236 | # base_path = str(pathlib.Path().resolve()) 237 | stop = base_path.find(PROGRAM_NAME) 238 | if stop == -1: 239 | #raise Exception(PROGRAM_NAME + " is not in file path") 240 | print(PROGRAM_NAME + " is not in file path") 241 | return base_path[: -len(MAIN_FOLDER)] + "/" 242 | 243 | 244 | if TMP: 245 | TEMP_DIR = tempfile.mkdtemp() 246 | BASE_PATH = TEMP_DIR + "/" 247 | FOLDER_PATH = _get_path() 248 | print(BASE_PATH) 249 | else: 250 | TEMP_DIR = None 251 | BASE_PATH = _get_path() 252 | FOLDER_PATH = _get_path() 253 | 254 | # with EIC 255 | EIC_NUM_DIM = 13 256 | EIC_PARAM_NAMES = [ 257 | "delta", 258 | "K", 259 | "n_1", 260 | "n_2", 261 | "gamma_min", 262 | "gamma_max", 263 | "gamma_break", 264 | "B", 265 | "R", 266 | "bb_temp", 267 | "L_nuc", 268 | "tau", 269 | "blob_dist", 270 | ] 271 | EIC_FORMATTED_PARAM_NAMES = [ 272 | r"$\delta$", 273 | r"log $K$", 274 | r"$n_1$", 275 | r"$n_2$", 276 | r"log $\gamma_{min}$", 277 | r"log $\gamma_{max}$", 278 | r"log $\gamma_{break}$", 279 | r"log $B$", 280 | r"log $R$", 281 | r"log $T_{BB}$", 282 | r"log $L_{nuc}$", 283 | r"$\tau$", 284 | r"log $D_b$", 285 | ] 286 | EIC_DETAILED_PARAM_NAMES = [ 287 | "doppler factor (delta)", 288 | "log K [cm^-3]", 289 | "alpha 1", 290 | "alpha 2", 291 | "log gamma_min", 292 | "log gamma_max", 293 | "log gamma_break", 294 | "log B", 295 | "log R [cm]", 296 | "log bb_temp", 297 | "log L_nuc", 298 | "log tau", 299 | "log blob_dist", 300 | ] 301 | EIC_PARAM_IS_LOG = [ 302 | False, 303 | True, 304 | False, 305 | False, 306 | True, 307 | True, 308 | True, 309 | True, 310 | True, 311 | True, 312 | True, 313 | True, 314 | True, 315 | ] 316 | 317 | # SSC 318 | SSC_NUM_DIM = 9 319 | SSC_PARAM_NAMES = [ 320 | "delta", 321 | "K", 322 | "n_1", 323 | "n_2", 324 | "gamma_min", 325 | "gamma_max", 326 | "gamma_break", 327 | "B", 328 | "R", 329 | ] 330 | SSC_FORMATTED_PARAM_NAMES = [ 331 | r"$\delta$", 332 | r"log $K$", 333 | r"$n_1$", 334 | r"$n_2$", 335 | r"log $\gamma_{min}$", 336 | r"log $\gamma_{max}$", 337 | r"log $\gamma_{break}$", 338 | r"log $B$", 339 | r"log $R$", 340 | ] 341 | SSC_DETAILED_PARAM_NAMES = [ 342 | "doppler factor (delta)", 343 | "log K [cm^-3]", 344 | "alpha 1", 345 | "alpha 2", 346 | "log gamma_min", 347 | "log gamma_max", 348 | "log gamma_break", 349 | "log B", 350 | "log R [cm]", 351 | ] 352 | SSC_PARAM_IS_LOG = [False, True, False, False, True, True, True, True, True] 353 | -------------------------------------------------------------------------------- /bjet_mcmc/run_Bjet_manual.py: -------------------------------------------------------------------------------- 1 | """ 2 | 3 | """ 4 | import numpy as np 5 | import matplotlib.pyplot as plt 6 | from astropy.io import ascii 7 | 8 | import blazar_model 9 | import blazar_utils 10 | from blazar_properties import * 11 | cmap = plt.get_cmap("tab10") 12 | filled_markers = ("o", "^", "<", ">", "8", "s", "p", "*", "h", "H", "D", "d", "P", "X") 13 | marker_size = 4 14 | linestyle_tuple = [ 15 | ('loosely dotted', (0, (1, 10))), 16 | ('dotted', (0, (1, 1))), 17 | ('densely dotted', (0, (1, 1))), 18 | ('long dash with offset', (5, (10, 3))), 19 | ('loosely dashed', (0, (5, 10))), 20 | ('dashed', (0, (5, 5))), 21 | ('densely dashed', (0, (5, 1))), 22 | 23 | ('loosely dashdotted', (0, (3, 10, 1, 10))), 24 | ('dashdotted', (0, (3, 5, 1, 5))), 25 | ('densely dashdotted', (0, (3, 1, 1, 1))), 26 | 27 | ('dashdotdotted', (0, (3, 5, 1, 5, 1, 5))), 28 | ('loosely dashdotdotted', (0, (3, 10, 1, 10, 1, 10))), 29 | ('densely dashdotdotted', (0, (3, 1, 1, 1, 1, 1)))] 30 | 31 | 32 | h = 4.135667662E-15 33 | 34 | def v_to_e(val): 35 | return val * h 36 | 37 | def e_to_v(val): 38 | return val / h 39 | 40 | 41 | Source = "J1010" 42 | 43 | #-----input files and plotting parameters-----# 44 | if Source == "J1010": 45 | Ylim = [1e-15,1e-9] #erg cm-2 s-1 46 | Xlim = [1e8,1e28] #Hz 47 | eic = False 48 | jet = False 49 | parameter_file = "parameter_files/J1010.par" 50 | instrument_data_file = "real_data/J1010_SED_reduced.dat" 51 | 52 | 53 | 54 | #-----run Bjet-----# 55 | model = blazar_model.file_make_SED(parameter_file=parameter_file, data_folder=None, executable=None, prev_files=False, 56 | verbose=True) 57 | 58 | 59 | #-----read instrumental SED-----# 60 | v_data, vFv_data, err_data, instrument_data, nubin_data = blazar_utils.read_data(instrument_data_file, instrument=True) 61 | # setting limits 62 | uplims = [False] * len(v_data) 63 | lolims = [False] * len(v_data) 64 | for i in range(len(err_data[1])): 65 | if err_data[0][i] == 0: 66 | uplims[i] = True 67 | err_data[0][i] = vFv_data[i] / 4 68 | if err_data[0][i] == -1: 69 | lolims[i] = True 70 | err_data[1][i] = vFv_data[i] / 4 71 | 72 | 73 | #-----read model SED-----# 74 | name_stem = 'test_bj' 75 | data_folder = DATA_FOLDER 76 | 77 | #blob synchrotron 78 | blob_sync = np.loadtxt(BASE_PATH + data_folder + "/" + name_stem + "_ss.dat", delimiter=' ') 79 | logv_blob_sync = blob_sync[:, 0] 80 | logvFv_blob_sync= blob_sync[:, 2] 81 | v_blob_sync = np.power(10, logv_blob_sync) 82 | vFv_blob_sync = np.power(10, logvFv_blob_sync) 83 | 84 | #blob SSC 85 | blob_ssc = np.loadtxt(BASE_PATH + data_folder + "/" + name_stem + "_cs.dat", delimiter=' ') 86 | logv_blob_ssc = blob_ssc[:, 0] 87 | logvFv_blob_ssc= blob_ssc[:, 2] 88 | v_blob_ssc = np.power(10, logv_blob_ssc) 89 | vFv_blob_ssc = np.power(10, logvFv_blob_ssc) 90 | logv_sum, logvFv_sum, v_sum, vFv_sum = blazar_model.add_data((logv_blob_sync, logvFv_blob_sync, v_blob_sync, vFv_blob_sync), 91 | file_suffix='cs', name_stem=name_stem, data_folder=data_folder) 92 | 93 | #blob SSC 2nd order 94 | blob_ssc2 = np.loadtxt(FOLDER_PATH + data_folder + "/" + name_stem + "_cs2.dat", delimiter=' ') 95 | logv_blob_ssc2 = blob_ssc2[:, 0] 96 | logvFv_blob_ssc2 = blob_ssc2[:, 2] 97 | v_blob_ssc2 = np.power(10, logv_blob_ssc2) 98 | vFv_blob_ssc2 = np.power(10, logvFv_blob_ssc2) 99 | logv_sum, logvFv_sum, v_sum, vFv_sum = blazar_model.add_data((logv_sum, logvFv_sum, v_sum, vFv_sum), 100 | file_suffix='cs2', name_stem=name_stem, data_folder=data_folder) 101 | 102 | if eic: 103 | # accretion disk 104 | disk = np.loadtxt(FOLDER_PATH + data_folder + "/" + name_stem + "_nuc.dat", delimiter=' ') 105 | logv_disk = disk[:, 0] 106 | logvFv_disk = disk[:, 2] 107 | v_disk = np.power(10, logv_disk) 108 | vFv_disk = np.power(10, logvFv_disk) 109 | logv_sum, logvFv_sum, v_sum, vFv_sum = blazar_model.add_data((logv_sum, logvFv_sum, v_sum, vFv_sum), 110 | file_suffix='nuc', name_stem=name_stem, data_folder=data_folder) 111 | 112 | # EIC blob-BLR 113 | eic_blr = np.loadtxt(FOLDER_PATH + data_folder + "/" + name_stem + "_ecs.dat", delimiter=' ') 114 | logv_eic_blr = eic_blr[:, 0] 115 | logvFv_eic_blr = eic_blr[:, 2] 116 | v_eic_blr = np.power(10, logv_eic_blr) 117 | vFv_eic_blr = np.power(10, logvFv_eic_blr) 118 | logv_sum, logvFv_sum, v_sum, vFv_sum = blazar_model.add_data((logv_sum, logvFv_sum, v_sum, vFv_sum), 119 | file_suffix='ecs', name_stem=name_stem, data_folder=data_folder) 120 | 121 | if jet: 122 | # #jet synchrotron 123 | jet_sync = np.loadtxt(FOLDER_PATH + data_folder + "/F_jet_syn.dat", delimiter=' ') 124 | v_jet_sync = jet_sync[:, 0] 125 | vFv_jet_sync = jet_sync[:, 2] 126 | logv_sum, logvFv_sum, v_sum, vFv_sum = blazar_model.add_data((logv_sum, logvFv_sum, v_sum, vFv_sum), 127 | file_suffix='syn', name_stem="F_jet", data_folder=data_folder) 128 | 129 | #jet SSC 130 | jet_ssc = np.loadtxt(FOLDER_PATH + data_folder + "/F_jet_com.dat", delimiter=' ') 131 | v_jet_ssc = jet_ssc[:, 0] 132 | vFv_jet_ssc = jet_ssc[:, 2] 133 | logv_sum, logvFv_sum, v_sum, vFv_sum = blazar_model.add_data((logv_sum, logvFv_sum, v_sum, vFv_sum), 134 | file_suffix='com', name_stem="F_jet", data_folder=data_folder) 135 | 136 | # EIC blob-jet (emitted from the blob) 137 | eic_jet = np.loadtxt(FOLDER_PATH + data_folder + "/" + name_stem + "_ecs_jet.dat", delimiter=' ') 138 | logv_eic_jet = eic_jet[:, 0] 139 | logvFv_eic_jet = eic_jet[:, 2] 140 | v_eic_jet = np.power(10, logv_eic_jet) 141 | vFv_eic_jet = np.power(10, logvFv_eic_jet) 142 | logv_sum, logvFv_sum, v_sum, vFv_sum = blazar_model.add_data((logv_sum, logvFv_sum, v_sum, vFv_sum), 143 | file_suffix='ecs_jet', name_stem=name_stem, data_folder=data_folder) 144 | 145 | # EIC jet-blob (emitted from the jet) 146 | jet_eic = np.loadtxt(FOLDER_PATH + data_folder + "/F_jet_eic.dat", delimiter=' ') 147 | v_jet_eic = jet_eic[:, 0] 148 | vFv_jet_eic = jet_eic[:, 2] 149 | logv_sum, logvFv_sum, v_sum, vFv_sum = blazar_model.add_data((logv_sum, logvFv_sum, v_sum, vFv_sum), 150 | file_suffix='eic', name_stem="F_jet", data_folder=data_folder) 151 | 152 | 153 | 154 | #-----plot instrumental SED-----# 155 | fig, ax = plt.subplots(figsize=(7.25,5)) 156 | 157 | list_intruments=[instrument_data[0]] 158 | v_data_inst = [v_data[0]] 159 | vFv_data_inst = [vFv_data[0]] 160 | err_data_inst_down = [err_data[0][0]] 161 | err_data_inst_up = [err_data[1][0]] 162 | nubin_data_inst_low= [nubin_data[0][0]] 163 | nubin_data_inst_high= [nubin_data[1][0]] 164 | uplims_inst = [uplims[0]] 165 | lolims_inst = [lolims[0]] 166 | tmp = 0 167 | tmp2 = 0 168 | p1 = [] 169 | marker1 = [] 170 | labels1 = [] 171 | n=0 172 | for i in range(1,len(instrument_data)): 173 | #cycle colors & markers 174 | if len(list_intruments)-tmp >= cmap.N: 175 | tmp += cmap.N 176 | color_index = len(list_intruments) - tmp 177 | if len(list_intruments)-tmp2 >= len(filled_markers): 178 | tmp2 += len(filled_markers) 179 | marker_index = len(list_intruments) - tmp2 180 | 181 | if instrument_data[i] != list_intruments[-1]: 182 | ax.errorbar(v_data_inst, vFv_data_inst, xerr=(nubin_data_inst_low, nubin_data_inst_high), yerr=(err_data_inst_down, err_data_inst_up), uplims = uplims_inst, 183 | lolims=lolims_inst, label=str(list_intruments[-1]), markersize=marker_size, elinewidth=1, color = cmap(color_index), 184 | fmt=filled_markers[marker_index-1]) 185 | list_intruments.append(instrument_data[i]) 186 | v_data_inst = [v_data[i]] 187 | vFv_data_inst = [vFv_data[i]] 188 | err_data_inst_down = [err_data[0][i]] 189 | err_data_inst_up = [err_data[1][i]] 190 | nubin_data_inst_low= [nubin_data[0][i]] 191 | nubin_data_inst_high= [nubin_data[1][i]] 192 | uplims_inst = [uplims[i]] 193 | lolims_inst = [lolims[i]] 194 | else: 195 | v_data_inst.append(v_data[i]) 196 | vFv_data_inst.append(vFv_data[i]) 197 | err_data_inst_down.append(err_data[0][i]) 198 | err_data_inst_up.append(err_data[1][i]) 199 | nubin_data_inst_low.append(nubin_data[0][i]) 200 | nubin_data_inst_high.append(nubin_data[1][i]) 201 | uplims_inst.append(uplims[i]) 202 | lolims_inst.append(lolims[i]) 203 | if i == len(instrument_data)-1: 204 | ax.errorbar(v_data_inst, vFv_data_inst, xerr=(nubin_data_inst_low, nubin_data_inst_high), yerr=(err_data_inst_down, err_data_inst_up), uplims = uplims_inst, 205 | lolims=lolims_inst, label=str(list_intruments[-1]), markersize=marker_size, elinewidth=1, color = cmap(color_index), 206 | fmt=filled_markers[marker_index-1]) 207 | 208 | legend1 = ax.legend(loc="upper center", ncol=4) 209 | ax.add_artist(legend1) 210 | 211 | p2 = [] 212 | labels2 = [] 213 | ax.plot(v_blob_sync, vFv_blob_sync, color=cmap(0), label=None, alpha=.7) 214 | labels2.append("Blob Sync. & SSC") 215 | p2.append(ax.plot(v_blob_ssc, vFv_blob_ssc, color=cmap(0), label="Blob Sync. & SSC", alpha=.7)) 216 | p2[-1] = p2[-1][0] 217 | if max(vFv_blob_ssc2)>Ylim[0]: 218 | labels2.append("Blob SSC 2nd order") 219 | p2.append(ax.plot(v_blob_ssc2, vFv_blob_ssc2, color=cmap(0), label="Blob SSC 2nd order", alpha=.7, ls=':')) 220 | p2[-1] = p2[-1][0] 221 | labels2.append("Disk") 222 | if eic: 223 | p2.append(ax.plot(v_disk, vFv_disk, color=cmap(2), label="disk", alpha=.7, ls='-.')) 224 | p2[-1] = p2[-1][0] 225 | if max(vFv_eic_blr)>Ylim[0]: 226 | labels2.append("EIC blob-BLR") 227 | p2.append(ax.plot(v_eic_blr, vFv_eic_blr, color=cmap(9), label="EIC blob-BLR", alpha=.7, ls=(0, (3, 1, 1, 1)))) 228 | p2[-1] = p2[-1][0] 229 | if jet: 230 | ax.plot(v_jet_sync, vFv_jet_sync, color='r', alpha=.7, ls=(0, (3, 1, 1, 1, 1, 1))) 231 | labels2.append("Jet Sync. & SSC") 232 | p2.append(ax.plot(v_jet_ssc, vFv_jet_ssc, color='r', label="Jet Sync. & SSC", alpha=.7, ls=(0, (3, 1, 1, 1, 1, 1)))) 233 | p2[-1] = p2[-1][0] 234 | 235 | labels2.append("EIC Blob-Jet") 236 | p2.append(ax.plot(v_eic_jet, vFv_eic_jet, color=cmap(4), label="EIC blob-jet", alpha=.7, ls='--')) 237 | p2[-1] = p2[-1][0] 238 | 239 | labels2.append("EIC Jet-Blob") 240 | p2.append(ax.plot(v_jet_eic, vFv_jet_eic, color=cmap(5), label="EIC jet-blob", alpha=.7, ls='--')) 241 | p2[-1] = p2[-1][0] 242 | labels2.append("Sum") 243 | p2.append(ax.plot(v_sum, vFv_sum, color='brown', alpha=.7)) 244 | p2[-1] = p2[-1][0] 245 | 246 | if Source[:5] == "OJ287": 247 | labels2.append("8.6 pc core Sync. & SSC") 248 | p2.append(ax.plot(v_core_sync, vFv_core_sync, color='r', alpha=.7, ls=(0, (1, 1)))) 249 | p2[-1] = p2[-1][0] 250 | ax.plot(v_core_SSC, vFv_core_SSC, color='r', alpha=.7, ls=(0, (1, 1))) 251 | 252 | lines, labels = ax.get_legend_handles_labels() 253 | legend2 = ax.legend(handles=p2, loc='lower center', labels=labels2, ncol=3) 254 | 255 | ax.loglog() 256 | ax.set_ylim(Ylim[0],Ylim[1]) 257 | ax.set_xlim(Xlim[0],Xlim[1]) 258 | ax.set_xlabel(r"Frequency $\nu$ (Hz)") 259 | ax.set_ylabel(r"Energy Flux $\nu F_{\nu}$ (erg cm$^{-2}$ s$^{-1})$") 260 | secax = ax.secondary_yaxis('right') 261 | secax = ax.secondary_xaxis('top', functions=(v_to_e, e_to_v)) 262 | secax.set_xlabel("Energy (eV)") 263 | plt.show() 264 | 265 | -------------------------------------------------------------------------------- /bjet_mcmc/blazar_mcmc.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import datetime 4 | import multiprocessing 5 | import shutil 6 | 7 | import emcee 8 | 9 | from bjet_mcmc import blazar_utils 10 | from bjet_mcmc import blazar_report 11 | from bjet_mcmc import blazar_properties 12 | from bjet_core import bj_core 13 | 14 | import glob 15 | import numpy as np 16 | import pathlib 17 | import subprocess 18 | import os 19 | import random 20 | from scipy import interpolate 21 | 22 | __all__ = [ 23 | "RESULTS_FOLDER", 24 | "DATA_FOLDER", 25 | "EXECUTABLE", 26 | "BASE_PATH", 27 | "configs", 28 | "EIC", 29 | "DIM", 30 | "redshift", 31 | "use_variability", 32 | "tau", 33 | "alpha2_limits", 34 | "model_type", 35 | "settings_and_transformation", 36 | "constant_and_numerical", 37 | "param_min_vals", 38 | "param_max_vals", 39 | "param_min_vals", 40 | "param_max_vals", 41 | "make_model", 42 | "log_prior", 43 | "random_params", 44 | "log_prob", 45 | "mcmc", 46 | ] 47 | 48 | # TODO Removed PROGRAM_NAME, so now results directory must go elsewhere (since that was the reference to it) 49 | RESULTS_FOLDER = "local_results" 50 | DATA_FOLDER = "sed_calculations" 51 | EXECUTABLE = "bjet_core/bj_core" 52 | BASE_PATH = blazar_properties.BASE_PATH 53 | 54 | configs = blazar_utils.read_configs() 55 | v_data, vFv_data, err_data = blazar_utils.read_data(configs["data_file"]) 56 | 57 | EIC = configs["eic"] 58 | DIM = 13 if EIC else 9 59 | if EIC: 60 | PARAM_IS_LOG = [ 61 | False, 62 | True, 63 | False, 64 | False, 65 | True, 66 | True, 67 | True, 68 | True, 69 | True, 70 | True, 71 | True, 72 | True, 73 | True, 74 | ] 75 | else: 76 | PARAM_IS_LOG = [False, True, False, False, True, True, True, True, True] 77 | 78 | redshift = configs["redshift"] 79 | use_variability = configs["use_variability"] 80 | tau = configs["tau_variability"] 81 | alpha2_limits = configs["alpha2_limits"] 82 | 83 | model_type = "1" if EIC else "0" 84 | settings_and_transformation = [ 85 | "3", 86 | BASE_PATH + DATA_FOLDER, 87 | model_type, 88 | str(redshift), 89 | "69.6", 90 | "0.57", 91 | ] 92 | constant_and_numerical = ["0", "1", "9.0e+17", "99", "5.0e+7", "1e+29", "temp_stem"] 93 | 94 | # mins maxes 95 | param_min_vals = [1.0, 0.0, 1.0, float(alpha2_limits[0]), 0.0, 3.0, 2.0, -4.0, 14.0] 96 | param_max_vals = [100.0, 8.0, 5.0, float(alpha2_limits[1]), 5.0, 8.0, 6.699, 0.0, 19.0] 97 | if EIC: 98 | extra_min = [1.0, 20.0, -10.0, 10.0] 99 | extra_max = [6.0, 50.0, 0.0, 21.0] 100 | param_min_vals = param_min_vals + extra_min 101 | param_max_vals = param_max_vals + extra_max 102 | param_min_vals = np.array(param_min_vals) 103 | param_max_vals = np.array(param_max_vals) 104 | 105 | 106 | def make_model(params, name_stem="run"): 107 | """ 108 | This function builds a model based on the provided parameters and name stem. It converts the parameters to logarithmic values where necessary. The model is built by executing a command using subprocess.run() and the output is saved to a file. The logarithmic wavelength and flux values are then extracted from the file and converted to linear values. Additional components are added to the model based on the name stem. Lastly, the built model is interpolated and combined with the existing model. 109 | 110 | :param params: The parameters for building the model. 111 | :type params: list[float] 112 | :param name_stem: The prefix for the output file names. 113 | :type name_stem: str 114 | :return: The logarithmic wavelength values, logarithmic flux values, linear wavelength values, and linear flux values. 115 | :rtype: tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray] 116 | 117 | A tuple containing the following elements: 118 | - logv (float[]): The logarithm of the frequency values. 119 | - logvFv (float[]): The logarithm of the flux values. 120 | - v (float[]): The frequency values. 121 | - vFv (float[]): The flux values. 122 | 123 | .. note:: This implementation uses subprocess.popen and should be rewritten in the future with bj_core.py methods. 124 | """ 125 | # convert to log 126 | # TODO rewrite this entire method using bj_core methods and without building a command string. 127 | params = params * 1.0 128 | for i in range(len(params)): 129 | if PARAM_IS_LOG[i]: 130 | params[i] = np.power(10, params[i]) 131 | if not EIC: 132 | command = ( 133 | settings_and_transformation 134 | + [str(val) for val in params] 135 | + constant_and_numerical[:-1] 136 | + [name_stem] 137 | ) 138 | else: 139 | command = ( 140 | settings_and_transformation 141 | + [str(val) for val in params[:9]] 142 | + constant_and_numerical[:2] 143 | + [str(params[-1])] 144 | ) 145 | command = command + [ 146 | str(params[9]), 147 | "2.0e+4", 148 | str(params[10]), 149 | str(params[11]), 150 | "5.5e+20", 151 | "9.0e-5", 152 | ] # EIC components 153 | command = command + constant_and_numerical[3:-1] + [name_stem] 154 | subprocess.run( 155 | [BASE_PATH + EXECUTABLE, *command], 156 | stderr=open(os.devnull, "wb"), 157 | stdout=open(os.devnull, "wb"), 158 | ) 159 | 160 | loaded_model = np.loadtxt( 161 | BASE_PATH + DATA_FOLDER + "/" + name_stem + "_ss.dat", delimiter=" " 162 | ) 163 | logv = loaded_model[:, 0] 164 | logvFv = loaded_model[:, 2] 165 | vFv = np.power(10, logvFv) 166 | 167 | stems = ["cs"] if not EIC else ["cs", "ecs", "cs2", "nuc"] 168 | for s in stems: 169 | loaded_model = np.loadtxt( 170 | BASE_PATH + DATA_FOLDER + "/" + name_stem + "_" + s + ".dat", delimiter=" " 171 | ) 172 | model_logv = loaded_model[:, 0] 173 | model_logvFv = loaded_model[:, 2] 174 | current_logv, current_logvFv, current_vFv = logv, logvFv, vFv 175 | 176 | new_lower = np.where(model_logv < logv[0])[0] 177 | new_higher = np.where(model_logv > logv[-1])[0] 178 | logv = np.concatenate( 179 | (model_logv[new_lower], current_logv, model_logv[new_higher]) 180 | ) 181 | logvFv = np.concatenate( 182 | (model_logvFv[new_lower], current_logvFv, model_logvFv[new_higher]) 183 | ) 184 | vFv = np.power(10, logvFv) 185 | 186 | overlap_start = np.where(logv >= max(model_logv[0], current_logv[0]))[0][0] 187 | overlap_end = np.where(logv <= min(model_logv[-1], current_logv[-1]))[0][-1] 188 | 189 | interpolation = interpolate.interp1d(model_logv, np.power(10, model_logvFv)) 190 | 191 | new_vFv = np.concatenate( 192 | ( 193 | np.zeros(overlap_start), 194 | interpolation(logv[overlap_start : overlap_end + 1]), 195 | np.zeros(len(logv) - overlap_end - 1), 196 | ) 197 | ) 198 | 199 | vFv = vFv + new_vFv 200 | logvFv = np.log10(vFv) 201 | return logv, logvFv, np.power(10, logv), vFv 202 | 203 | 204 | def log_prior(params): 205 | """ 206 | This function calculates the log prior probability for a given set of parameters. 207 | 208 | Args: 209 | params (tuple): A tuple containing the following parameters: 210 | - delta (float): The value of delta. 211 | - K (float): The value of K. 212 | - n1 (float): The value of n1. 213 | - n2 (float): The value of n2. 214 | - gamma_min (float): The value of gamma_min. 215 | - gamma_max (float): The value of gamma_max. 216 | - gamma_break (float): The value of gamma_break. 217 | - B (float): The value of B. 218 | - R (float): The value of R. 219 | - other_params (tuple): Optional additional parameters. 220 | 221 | Returns: 222 | float: The log prior value. If any of the parameters violate the constraints, it returns negative infinity (-inf). Otherwise, it returns 0. 223 | 224 | :param params: The input parameters to calculate the log prior probability. 225 | :type params: tuple 226 | 227 | :return: The log prior probability. 228 | :rtype: float 229 | """ 230 | delta, K, n1, n2, gamma_min, gamma_max, gamma_break, B, R, *other_params = params 231 | if ( 232 | n1 > n2 233 | or gamma_min > gamma_max 234 | or gamma_break < gamma_min 235 | or gamma_break > gamma_max 236 | ): 237 | return -np.inf 238 | # testing if between min and max 239 | for i in range(len(params)): 240 | # gamma break is solely constrained by gamma_min and gamma_max 241 | if i != 6 and (param_min_vals[i] > params[i] or param_max_vals[i] < params[i]): 242 | return -np.inf 243 | if use_variability: 244 | tau_var = tau * 60 * 60 # to seconds 245 | c = 2.997924 * 1.0e10 246 | R = np.power(10, R) 247 | if tau_var < (1 + redshift) / c * R / delta: 248 | return -np.inf 249 | return 0 250 | 251 | 252 | def random_params(): 253 | """ 254 | Generates random parameters within given range and checks if they have finite log prior values and are within specified minimum and maximum values. 255 | 256 | Returns: 257 | numpy.ndarray: Array of random parameters. 258 | 259 | Raises: 260 | None. 261 | 262 | Examples: 263 | >>> random_params() 264 | array([0.5, 1.2, 0.8]) 265 | 266 | :return: Randomly generated parameters within the specified range. 267 | :rtype: numpy.ndarray 268 | """ 269 | parameter_size = param_max_vals - param_min_vals 270 | parameters = param_min_vals + parameter_size * np.random.rand(DIM) 271 | while not np.isfinite(log_prior(parameters)): 272 | parameters = param_min_vals + parameter_size * np.random.rand(DIM) 273 | return parameters 274 | 275 | 276 | def log_prob(params): 277 | """ 278 | 279 | This function calculates the log probability for a given set of parameters. 280 | 281 | The array should contain the following elements in order: 282 | - **delta**: A float representing a prior value 283 | - **K**: An integer representing a prior value 284 | - **n1**: An integer representing a prior value 285 | - **n2**: An integer representing a prior value 286 | - **gamma_min**: A float representing a prior value 287 | - **gamma_max**: A float representing a prior value 288 | - **gamma_break**: A float representing a prior value 289 | - **B**: A float representing a prior value 290 | - **R**: A float representing a prior value 291 | - **\*other_params**: Additional parameters (optional) 292 | 293 | :param params: A list of parameters. 294 | :type params: list 295 | :return: The log probability for the given parameters. It returns -inf if any of the following conditions are met: 296 | 297 | - **n1 > n2** 298 | - **gamma_min > gamma_max** 299 | - **gamma_break < gamma_min** 300 | - **gamma_break > gamma_max** 301 | - Any parameter falls outside the specified range (param_min_vals and param_max_vals) 302 | 303 | :rtype: float 304 | """ 305 | name_stem = "run_" + str(random.getrandbits(60)) 306 | 307 | # prior 308 | delta, K, n1, n2, gamma_min, gamma_max, gamma_break, B, R, *other_params = params 309 | if ( 310 | n1 > n2 311 | or gamma_min > gamma_max 312 | or gamma_break < gamma_min 313 | or gamma_break > gamma_max 314 | ): 315 | return -np.inf 316 | # testing if between min and max 317 | for i in range(len(params)): 318 | # gamma break is solely constrained by gamma_min and gamma_max 319 | if i != 6 and (param_min_vals[i] > params[i] or param_max_vals[i] < params[i]): 320 | return -np.inf 321 | if use_variability: 322 | tau_var = tau * 60 * 60 # to seconds 323 | c = 2.997924 * 1.0e10 324 | R = np.power(10, R) 325 | if tau_var < (1 + redshift) / c * R / delta: 326 | return -np.inf 327 | 328 | model = make_model(params, name_stem) 329 | 330 | # calculate chi squared 331 | func = interpolate.interp1d(model[0], model[1], fill_value="extrapolate") 332 | chi_sq = np.sum( 333 | ((vFv_data - np.power(10, func(np.log10(v_data)))) / err_data) ** 2.0 334 | ) 335 | for f in glob.glob(BASE_PATH + DATA_FOLDER + "/" + name_stem + "_*"): 336 | os.remove(f) 337 | 338 | return -0.5 * chi_sq 339 | 340 | 341 | def mcmc(p0=None): 342 | """ 343 | :param p0: The initial parameter values for each walker. If not provided, random parameter values will be generated. 344 | :type p0: numpy.array or None 345 | :return: A tuple containing the sampler object and the directory where the results are saved. 346 | :rtype: tuple[emcee.EnsembleSampler, str] 347 | 348 | This function performs a Markov Chain Monte Carlo (MCMC) simulation using the emcee library in Python. The MCMC simulation is used to sample from the posterior distribution of a specified likelihood function. The simulation starts from an initial set of parameter values (p0) and iteratively updates these values to explore the parameter space and converge to the posterior distribution. 349 | 350 | If p0 is provided, the function prints the first element of p0. 351 | The function then checks for "folder_label" and "description" in the "configs" dictionary. If "folder_label" is present, it assigns its value to the variable "folder_label", otherwise it assigns the default value "run". If "description" is present, it assigns its value to the variable "description", otherwise it assigns None. 352 | 353 | The function then creates a directory to store the results using the current date and time. 354 | It creates a "backend.h5" file for storing the backend data. 355 | It creates a "basic_info.txt" file to store basic information about the simulation, including the folder name, description (if provided), and configurations. If p0 is provided, it indicates that p0 was given in the file. 356 | 357 | If the "parallel" configuration is set to True in the "configs" dictionary, the function creates a multiprocessing pool to run the simulation in parallel. The number of processes in the pool is determined by the "cores" configuration in "configs" (default value is the number of available CPU cores). If "parallel" is False, the pool is set to None. 358 | 359 | The function then creates an emcee HDFBackend object to store the backend data. 360 | It resets the backend with the specified number of walkers and dimensions. 361 | 362 | If p0 is not provided, it generates random initial parameter values for each walker. 363 | 364 | The function creates an emcee EnsembleSampler object with the specified number of walkers, dimensions, log probability function, backend, move, and pool. 365 | 366 | It prints a message indicating the start of the MCMC simulation. 367 | 368 | The function records the start time and runs the MCMC simulation using the run_mcmc() method of the sampler. 369 | 370 | If the "parallel" configuration is True, it closes the multiprocessing pool. 371 | 372 | The function records the end time and appends the total simulation time to the "basic_info.txt" file. 373 | 374 | Finally, the function calls the "show_results()" and "save_plots_and_info()" functions from the blazar_report module with various parameters to display and save the simulation results. 375 | 376 | The function returns a tuple containing the MCMC sampler and the directory where the results are saved. 377 | """ 378 | if p0 is not None: 379 | print(p0[0]) 380 | if "folder_label" in configs: 381 | folder_label = configs["folder_label"] 382 | else: 383 | folder_label = "run" 384 | if "description" in configs: 385 | description = configs["description"] 386 | else: 387 | description = None 388 | 389 | now = datetime.datetime.now() 390 | date_string = now.strftime("%Y-%m-%d-%H:%M:%S") 391 | directory = RESULTS_FOLDER + "/" + folder_label + "_" + date_string 392 | 393 | os.mkdir(BASE_PATH + directory) 394 | 395 | backend = directory + "/backend.h5" 396 | 397 | # make file with basic info 398 | with open(BASE_PATH + directory + "/basic_info.txt", "w") as f: 399 | f.write("folder name: ") 400 | f.write(directory) 401 | if description is not None: 402 | f.write("\nreport description: ") 403 | f.write(description) 404 | f.write("\n") 405 | f.write("\nconfigurations:\n") 406 | f.write(str(configs)) 407 | if p0 is not None: 408 | f.write("\np0 given\n") 409 | 410 | if configs["parallel"]: 411 | if "cores" not in configs: 412 | pool = multiprocessing.Pool() 413 | else: 414 | pool = multiprocessing.Pool(processes=configs["cores"]) 415 | else: 416 | pool = None 417 | backend = emcee.backends.HDFBackend(BASE_PATH + backend) 418 | backend.reset(configs["n_walkers"], DIM) 419 | 420 | if p0 is None: 421 | p0 = np.array([random_params() for _ in range(configs["n_walkers"])]) 422 | 423 | sampler = emcee.EnsembleSampler( 424 | configs["n_walkers"], 425 | DIM, 426 | log_prob, 427 | backend=backend, 428 | moves=[(emcee.moves.StretchMove(live_dangerously=True), 1.0)], 429 | pool=pool, 430 | ) 431 | 432 | print("starting mcmc") 433 | start = datetime.datetime.now() 434 | sampler.run_mcmc(p0, configs["n_steps"], progress=True) 435 | end = datetime.datetime.now() 436 | if configs["parallel"]: 437 | pool.close() 438 | 439 | with open(BASE_PATH + directory + "/basic_info.txt", "a") as f: 440 | f.write("\ntime: ") 441 | f.write(str(end - start)) 442 | f.write("\n") 443 | 444 | blazar_report.show_results(sampler, str(end - start), configs=configs) 445 | blazar_report.save_plots_and_info( 446 | configs, 447 | (v_data, vFv_data, err_data), 448 | param_min_vals, 449 | param_max_vals, 450 | folder=directory, 451 | sampler=sampler, 452 | use_sampler=True, 453 | description=description, 454 | time=str(end - start), 455 | redshift=redshift, 456 | eic=EIC, 457 | ) 458 | 459 | return sampler, directory 460 | 461 | 462 | def main_cli(): 463 | """ 464 | This function is the entry point for the command-line interface of the software. It performs the following steps: 465 | 466 | 1. It initializes the variable `p0` to `None`. 467 | 468 | 2. It calls the `mcmc()` function with the `p0` variable as an argument. The `mcmc()` function returns two values - `sampler` and `directory`. These values are assigned to the variables `sampler` and `directory` respectively. 469 | 470 | 3. If the value of `blazar_properties.TMP` is true, it moves the directory specified by `BASE_PATH + directory` to `blazar_properties.FOLDER_PATH + directory` using the `shutil.move()` function. It also removes the temporary directory specified by `blazar_properties.TEMP_DIR` using the `shutil.rmtree()` function. 471 | 472 | :return: None 473 | :rtype: None 474 | """ 475 | # p0_file = "local_results/3C66A_b6_eic_2022-06-08-20:17:26/backend.h5" 476 | # reader = emcee.backends.HDFBackend(BASE_PATH + p0_file, read_only=True) 477 | # p0 = reader.get_last_sample().coords 478 | p0 = None 479 | sampler, directory = mcmc(p0=p0) 480 | if blazar_properties.TMP: 481 | shutil.move(BASE_PATH + directory, blazar_properties.FOLDER_PATH + directory) 482 | shutil.rmtree(blazar_properties.TEMP_DIR) 483 | 484 | 485 | if __name__ == "__main__": 486 | main_cli() 487 | -------------------------------------------------------------------------------- /bjet_mcmc/user_SED_plot.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | """ 4 | Name: user_SED_plot.py 5 | 6 | Script to produce custom SED plot. The user can change anything in this script without impacting 7 | the standard behavior of Bjet_MCMC. 8 | 9 | All standard outputs of Bjet_MCMC can be re-created with the option Full_outputs = True 10 | 11 | """ 12 | import os 13 | import sys 14 | import emcee 15 | import numpy as np 16 | import matplotlib.pyplot as plt 17 | from scipy import interpolate 18 | 19 | from bjet_mcmc import blazar_model 20 | from bjet_mcmc import blazar_report 21 | from bjet_mcmc import blazar_utils 22 | from bjet_mcmc import blazar_plots 23 | from bjet_mcmc.blazar_properties import * 24 | 25 | __all__ = ["e_to_v", "v_to_e"] 26 | 27 | cmap = plt.get_cmap("tab10") 28 | filled_markers = ("o", "^", "<", ">", "8", "s", "p", "*", "h", "H", "D", "d", "P", "X") 29 | marker_size = 4 30 | params = { #'backend': 'ps', 31 | "axes.labelsize": 14, 32 | "xtick.labelsize": 12, 33 | "ytick.labelsize": 12, 34 | "legend.fontsize": 12, 35 | } 36 | plt.rcParams.update(params) 37 | plt.close() 38 | 39 | 40 | # -----FLAGS-----# 41 | 42 | # recreate all text files and plots outputs 43 | Full_outputs = True 44 | 45 | # user defined SED plot boundaries 46 | boundaries = "default" 47 | # if you want to set boundaries (nu in Hz, nuFnu in erg.cm-2.s-1): 48 | # boundaries = [nu_min,nu_max, nuFnu_min, nuFnu_max] 49 | 50 | # type of residual plot to be displayed 51 | residual = "sigma" 52 | 53 | # frequency/energy conversion 54 | h = 4.135667662e-15 55 | 56 | 57 | def v_to_e(val): 58 | return val * h 59 | 60 | 61 | def e_to_v(val): 62 | return val / h 63 | 64 | 65 | if __name__ == "__main__": 66 | backend_file = "" 67 | if len(sys.argv) > 2: 68 | print("too many arguments. only pass the relative path to the .h5 file") 69 | elif len(sys.argv) == 2: 70 | backend_file = sys.argv[1] 71 | else: 72 | backend_file = input("Enter relative path to backend file: ") 73 | 74 | # example: local_results/J1010/J1010_2023-07-04-23:03:45/backend.h5 75 | # local_results/J1010_2024-08-12-16:47:25/backend.h5 76 | folder = backend_file[: backend_file.rfind("/")] 77 | 78 | if os.path.exists(FOLDER_PATH + folder + "/info.txt"): 79 | info = blazar_report.parse_info_doc(folder + "/info.txt") 80 | configs = info["configs"] 81 | print(configs) 82 | else: 83 | configs = blazar_utils.read_configs() 84 | data = blazar_utils.read_data(configs["data_file"], instrument=True) 85 | 86 | v_data, vFv_data, err_data, instrument_data, nubin_data = data 87 | # setting limits 88 | uplims = [False] * len(v_data) 89 | lolims = [False] * len(v_data) 90 | for i in range(len(err_data[1])): 91 | if err_data[0][i] == 0: 92 | uplims[i] = True 93 | err_data[0][i] = vFv_data[i] / 4 94 | if err_data[0][i] == -1: 95 | lolims[i] = True 96 | err_data[1][i] = vFv_data[i] / 4 97 | 98 | redshift = configs["redshift"] 99 | discard = configs["discard"] 100 | eic = configs["eic"] 101 | fixed_params = configs["fixed_params"] 102 | 103 | param_min_vals, param_max_vals = blazar_utils.min_max_parameters( 104 | eic=eic, fixed_params=fixed_params 105 | ) 106 | reader = emcee.backends.HDFBackend(FOLDER_PATH + backend_file) 107 | 108 | # if you get an error about not running with store=true here, it might be 109 | # because the script didn't find you backend.h5 file. Try running 110 | # user_SED from the root Bjet_MCMC directory insted of in 111 | # Bjet_MCMC/bjet_mcmc 112 | chain = reader.get_chain(discard=discard) 113 | # all parameters values: 114 | flat_samples = reader.get_chain(flat=True, discard=discard) 115 | 116 | log_probs = reader.get_log_prob(discard=discard) 117 | flat_log_probs = reader.get_log_prob(flat=True, discard=discard) 118 | 119 | best_log_prob, best_params = blazar_report.get_best_log_prob_and_params( 120 | log_probs=flat_log_probs, flat_chain=flat_samples 121 | ) 122 | indices_within_1sigma = blazar_report.get_indices_within_1sigma( 123 | flat_log_probs, eic=eic, ndim=modelProperties(eic).NUM_DIM 124 | ) 125 | 126 | name_stem = "plot" 127 | command_params_1, command_params_2 = blazar_model.command_line_sub_strings( 128 | name_stem=name_stem, redshift=redshift, prev_files=False, eic=eic 129 | ) 130 | command_params_2[3] = "99" # number of points used to make SED 131 | 132 | best_model = blazar_model.make_model( 133 | best_params, 134 | name_stem=name_stem, 135 | redshift=redshift, 136 | command_params_1=command_params_1, 137 | command_params_2=command_params_2, 138 | eic=eic, 139 | fixed_params=fixed_params, 140 | ) 141 | 142 | min_per_param, max_per_param = blazar_plots.get_params_1sigma_ranges( 143 | flat_samples, indices_within_1sigma, eic=eic, fixed_params=fixed_params 144 | ) 145 | to_plot = np.concatenate((np.array(min_per_param), np.array(max_per_param))) 146 | logv = best_model[0].copy() 147 | lowest_per_point, highest_per_point = blazar_plots.get_min_max_per_point( 148 | logv, 149 | to_plot, 150 | name_stem=name_stem, 151 | redshift=redshift, 152 | command_params_1=command_params_1, 153 | command_params_2=command_params_2, 154 | eic=eic, 155 | fixed_params=fixed_params, 156 | ) 157 | 158 | if residual: 159 | fig, (ax, ax1) = plt.subplots( 160 | 2, sharex="all", gridspec_kw={"height_ratios": [6, 1.5]}, figsize=(9, 7) 161 | ) 162 | else: 163 | fig, ax = plt.subplots() 164 | plt.xlabel(r"Frequency $\nu$ (Hz)") 165 | ax.set_ylabel(r"Energy Flux $\nu F_{\nu}$ (erg cm$^{-2}$ s$^{-1})$") 166 | 167 | ax.set_yscale("log") 168 | plt.xscale("log") 169 | 170 | ax.fill_between( 171 | np.power(10, logv), 172 | np.power(10, lowest_per_point), 173 | np.power(10, highest_per_point), 174 | alpha=0.5, 175 | label=r"Within 1$\sigma$", 176 | ) 177 | 178 | ax.plot(best_model[2], best_model[3], label="Best model", zorder=2.5, alpha=0.8) 179 | 180 | # This line re-run the model to import the good associated .dat files to plot 181 | blazar_model.make_model( 182 | best_params, 183 | name_stem=name_stem, 184 | redshift=redshift, 185 | command_params_1=command_params_1, 186 | command_params_2=command_params_2, 187 | eic=eic, 188 | fixed_params=fixed_params, 189 | ) 190 | 191 | synchrotron_model = np.loadtxt( 192 | FOLDER_PATH + "sed_calculations/" + name_stem + "_ss.dat", delimiter=" " 193 | ) 194 | logv_synchrotron = synchrotron_model[:, 0] 195 | logvFv_synchrotron = synchrotron_model[:, 2] 196 | v_synchrotron = np.power(10, logv_synchrotron) 197 | vFv_synchrotron = np.power(10, logvFv_synchrotron) 198 | 199 | compton_model = np.loadtxt( 200 | FOLDER_PATH + "sed_calculations/" + name_stem + "_cs.dat", delimiter=" " 201 | ) 202 | logv_compton = compton_model[:, 0] 203 | logvFv_compton = compton_model[:, 2] 204 | v_compton = np.power(10, logv_compton) 205 | vFv_compton = np.power(10, logvFv_compton) 206 | 207 | cs2 = np.loadtxt( 208 | FOLDER_PATH + "sed_calculations/" + name_stem + "_cs2.dat", delimiter=" " 209 | ) 210 | logv_cs2 = cs2[:, 0] 211 | logvFv_cs2 = cs2[:, 2] 212 | v_cs2 = np.power(10, logv_cs2) 213 | vFv_cs2 = np.power(10, logvFv_cs2) 214 | 215 | if boundaries == "default": 216 | ax.set_xlim(5e8, 1e28) 217 | new_min, new_max = blazar_plots.scale_to_values( 218 | data[1], lower_adjust_multiplier=20, upper_adjust_multiplier=15 219 | ) 220 | ax.set_ylim(new_min, new_max) 221 | else: 222 | ax.set_xlim(boundaries[0], boundaries[1]) 223 | ax.set_ylim(boundaries[2], boundaries[3]) 224 | 225 | ax.plot(v_synchrotron, vFv_synchrotron, "k--", label="Synchrotron", alpha=0.5) 226 | ax.plot(v_compton, vFv_compton, "k-", label="Self Compton", alpha=0.5) 227 | if max(vFv_cs2) > new_min: 228 | ax.plot(v_cs2, vFv_cs2, "-", label="2nd Order SC") 229 | 230 | if eic: 231 | ecs = np.loadtxt( 232 | FOLDER_PATH + "sed_calculations/" + name_stem + "_ecs.dat", delimiter=" " 233 | ) 234 | logv_ecs = ecs[:, 0] 235 | logvFv_ecs = ecs[:, 2] 236 | v_ecs = np.power(10, logv_ecs) 237 | vFv_ecs = np.power(10, logvFv_ecs) 238 | 239 | nuc = np.loadtxt( 240 | FOLDER_PATH + "sed_calculations/" + name_stem + "_nuc.dat", delimiter=" " 241 | ) 242 | logv_nuc = nuc[:, 0] 243 | logvFv_nuc = nuc[:, 2] 244 | v_nuc = np.power(10, logv_nuc) 245 | vFv_nuc = np.power(10, logvFv_nuc) 246 | 247 | if max(vFv_ecs) > new_min: 248 | ax.plot(v_ecs, vFv_ecs, "-", label="EIC") 249 | ax.plot(v_nuc, vFv_nuc, "-", label="nucleus") 250 | 251 | list_intruments = [instrument_data[0]] 252 | v_data_inst = [v_data[0]] 253 | vFv_data_inst = [vFv_data[0]] 254 | err_data_inst_down = [err_data[0][0]] 255 | err_data_inst_up = [err_data[1][0]] 256 | nubin_data_inst_low = [nubin_data[0][0]] 257 | nubin_data_inst_high = [nubin_data[1][0]] 258 | uplims_inst = [uplims[0]] 259 | lolims_inst = [lolims[0]] 260 | tmp = 0 261 | tmp2 = 0 262 | 263 | for i in range(1, len(instrument_data)): 264 | # cycle colors & markers 265 | if len(list_intruments) - tmp >= cmap.N: 266 | tmp += cmap.N 267 | color_index = len(list_intruments) - tmp 268 | if len(list_intruments) - tmp2 >= len(filled_markers): 269 | tmp2 += len(filled_markers) 270 | marker_index = len(list_intruments) - tmp2 271 | 272 | if instrument_data[i] != list_intruments[-1]: 273 | ax.errorbar( 274 | v_data_inst, 275 | vFv_data_inst, 276 | xerr=(nubin_data_inst_low, nubin_data_inst_high), 277 | yerr=(err_data_inst_down, err_data_inst_up), 278 | uplims=uplims_inst, 279 | lolims=lolims_inst, 280 | label=str(list_intruments[-1]), 281 | markersize=marker_size, 282 | elinewidth=1, 283 | color=cmap(color_index), 284 | fmt=filled_markers[marker_index - 1], 285 | ) 286 | list_intruments.append(instrument_data[i]) 287 | v_data_inst = [v_data[i]] 288 | vFv_data_inst = [vFv_data[i]] 289 | err_data_inst_down = [err_data[0][i]] 290 | err_data_inst_up = [err_data[1][i]] 291 | nubin_data_inst_low = [nubin_data[0][i]] 292 | nubin_data_inst_high = [nubin_data[1][i]] 293 | uplims_inst = [uplims[i]] 294 | lolims_inst = [lolims[i]] 295 | else: 296 | v_data_inst.append(v_data[i]) 297 | vFv_data_inst.append(vFv_data[i]) 298 | err_data_inst_down.append(err_data[0][i]) 299 | err_data_inst_up.append(err_data[1][i]) 300 | nubin_data_inst_low.append(nubin_data[0][i]) 301 | nubin_data_inst_high.append(nubin_data[1][i]) 302 | uplims_inst.append(uplims[i]) 303 | lolims_inst.append(lolims[i]) 304 | if i == len(instrument_data) - 1: 305 | ax.errorbar( 306 | v_data_inst, 307 | vFv_data_inst, 308 | xerr=(nubin_data_inst_low, nubin_data_inst_high), 309 | yerr=(err_data_inst_down, err_data_inst_up), 310 | uplims=uplims_inst, 311 | lolims=lolims_inst, 312 | label=str(list_intruments[-1]), 313 | markersize=marker_size, 314 | elinewidth=1, 315 | color=cmap(color_index), 316 | fmt=filled_markers[marker_index - 1], 317 | ) 318 | 319 | ax.legend(loc="upper center", ncol=4) 320 | 321 | secax = ax.secondary_xaxis("top", functions=(v_to_e, e_to_v)) 322 | secax.set_xlabel("Energy (eV)") 323 | 324 | if residual: 325 | 326 | f_best = interpolate.interp1d( 327 | best_model[2], best_model[3], fill_value="extrapolate" 328 | ) 329 | f_low = interpolate.interp1d( 330 | best_model[2], np.power(10, lowest_per_point), fill_value="extrapolate" 331 | ) 332 | f_high = interpolate.interp1d( 333 | best_model[2], np.power(10, highest_per_point), fill_value="extrapolate" 334 | ) 335 | 336 | ax1.hlines(0, best_model[2][0], best_model[2][-1]) 337 | 338 | if residual == "delta": 339 | ax1.fill_between( 340 | best_model[2], 341 | f_high(best_model[2]) / f_best(best_model[2]) - 1, 342 | -f_best(best_model[2]) / f_low(best_model[2]) + 1, 343 | alpha=0.5, 344 | zorder=1, 345 | ) 346 | if residual == "sigma": 347 | for i in range(len(err_data[1])): 348 | if err_data[1][i] == 0: 349 | err_data[0][i] = 0 350 | 351 | err_low = err_data[0] 352 | err_high = err_data[1] 353 | 354 | diff = vFv_data - f_best(v_data) 355 | # check if data is above or below model flux points, True if above 356 | sign = diff > 0 357 | # transform err_data to consider ULs (P=95% when below, P=5% when above) 358 | if_UL = err_data[0] == 0 359 | err_data[0] += if_UL * blazar_utils.chi_squared_Limit_to_err( 360 | 0.95, f_best(v_data), vFv_data 361 | ) 362 | err_data[1] += if_UL * blazar_utils.chi_squared_Limit_to_err( 363 | 0.05, f_best(v_data), vFv_data 364 | ) 365 | # transform err_data to consider LLs (P=95% when above, P=5% when below) 366 | if_LL = err_data[0] == -1 367 | err_data[0] += if_LL * blazar_utils.chi_squared_Limit_to_err( 368 | 0.05, f_best(v_data), vFv_data 369 | ) 370 | err_data[1] += if_LL * blazar_utils.chi_squared_Limit_to_err( 371 | 0.95, f_best(v_data), vFv_data 372 | ) 373 | 374 | vFv_sigma = ( 375 | sign * (vFv_data - f_best(v_data)) / err_low 376 | - ~sign * (f_best(v_data) - vFv_data) / err_high 377 | ) 378 | vFv_sigma_inst = [vFv_sigma[0]] 379 | 380 | list_intruments = [instrument_data[0]] 381 | v_data_inst = [v_data[0]] 382 | vFv_data_inst = [vFv_data[0]] 383 | err_data_inst_down = [err_low[0]] 384 | err_data_inst_up = [err_high[0]] 385 | uplims_inst = [uplims[0]] 386 | lolims_inst = [lolims[0]] 387 | tmp = 0 388 | tmp2 = 0 389 | 390 | for i in range(1, len(instrument_data)): 391 | # cycle colors & markers 392 | if len(list_intruments) - tmp >= cmap.N: 393 | tmp += cmap.N 394 | color_index = len(list_intruments) - tmp 395 | if len(list_intruments) - tmp2 >= len(filled_markers): 396 | tmp2 += len(filled_markers) 397 | marker_index = len(list_intruments) - tmp2 398 | 399 | if instrument_data[i] != list_intruments[-1]: 400 | if residual == "delta": 401 | ax1.errorbar( 402 | v_data_inst, 403 | vFv_data_inst / f_best(v_data_inst) - 1, 404 | yerr=( 405 | err_data_inst_down / f_best(v_data_inst), 406 | err_data_inst_up / f_best(v_data_inst), 407 | ), 408 | uplims=uplims_inst, 409 | lolims=lolims_inst, 410 | markersize=4, 411 | elinewidth=1, 412 | color=cmap(color_index), 413 | fmt=filled_markers[marker_index - 1], 414 | ) 415 | if residual == "sigma": 416 | ax1.errorbar( 417 | v_data_inst, 418 | vFv_sigma_inst, 419 | yerr=(1), 420 | uplims=uplims_inst, 421 | lolims=lolims_inst, 422 | markersize=4, 423 | elinewidth=1, 424 | color=cmap(color_index), 425 | fmt=filled_markers[marker_index - 1], 426 | ) 427 | vFv_sigma_inst = [vFv_sigma[i]] 428 | 429 | list_intruments.append(instrument_data[i]) 430 | v_data_inst = [v_data[i]] 431 | vFv_data_inst = [vFv_data[i]] 432 | err_data_inst_down = [err_low[i]] 433 | err_data_inst_up = [err_high[i]] 434 | uplims_inst = [uplims[i]] 435 | lolims_inst = [lolims[i]] 436 | else: 437 | if residual == "sigma": 438 | vFv_sigma_inst.append(vFv_sigma[i]) 439 | v_data_inst.append(v_data[i]) 440 | vFv_data_inst.append(vFv_data[i]) 441 | err_data_inst_down.append(err_low[i]) 442 | err_data_inst_up.append(err_high[i]) 443 | uplims_inst.append(uplims[i]) 444 | lolims_inst.append(lolims[i]) 445 | 446 | if i == len(instrument_data) - 1: 447 | if residual == "delta": 448 | ax1.errorbar( 449 | v_data_inst, 450 | vFv_data_inst / f_best(v_data_inst) - 1, 451 | yerr=( 452 | err_data_inst_down / f_best(v_data_inst), 453 | err_data_inst_up / f_best(v_data_inst), 454 | ), 455 | uplims=uplims_inst, 456 | lolims=lolims_inst, 457 | markersize=4, 458 | elinewidth=1, 459 | color=cmap(color_index), 460 | fmt=filled_markers[marker_index - 1], 461 | ) 462 | if residual == "sigma": 463 | ax1.errorbar( 464 | v_data_inst, 465 | vFv_sigma_inst, 466 | yerr=(1), 467 | uplims=uplims_inst, 468 | lolims=lolims_inst, 469 | markersize=4, 470 | elinewidth=1, 471 | color=cmap(color_index), 472 | fmt=filled_markers[marker_index - 1], 473 | ) 474 | if residual == "delta": 475 | ax1.set_ylim( 476 | min(vFv_data / f_best(v_data) - 1) * 2, 477 | max(vFv_data / f_best(v_data) - 1) * 2, 478 | ) 479 | ax1.set_ylabel("Residuals") 480 | if residual == "sigma": 481 | ax1.set_ylabel(r"$\Delta \sigma$") 482 | ax1.set_ylim(min(vFv_sigma) * 1.5, max(vFv_sigma) * 1.5) 483 | ax1.yaxis.get_ticklocs(minor=True) 484 | ax1.xaxis.get_ticklocs(minor=True) 485 | ax1.minorticks_on() 486 | 487 | plt.tight_layout() 488 | # plt.show() 489 | plt.savefig(BASE_PATH + folder + "/user_plot_SED.svg") 490 | 491 | if Full_outputs: 492 | blazar_report.save_plots_and_info( 493 | configs, 494 | (v_data, vFv_data, err_data), 495 | param_min_vals, 496 | param_max_vals, 497 | folder=folder, 498 | samples=(chain, flat_samples, log_probs, flat_log_probs), 499 | use_samples=True, 500 | redshift=redshift, 501 | eic=eic, 502 | verbose=True, 503 | ) 504 | -------------------------------------------------------------------------------- /bjet_mcmc/blazar_run_mcmc.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | """ 4 | Program Purpose: Implement the mcmc. Run the file to run the MCMC as a script 5 | using a parameter file. 6 | 7 | Parameters are always listed in the following order: 8 | [delta, K, n1, n2, gamma_min, gamma_max, gamma_break, B, R] 9 | 10 | All parameters are the logarithm of the true value except for delta, n1, and n2 11 | 12 | =================== ============================= ====== 13 | Parameter Description Scale 14 | =================== ============================= ====== 15 | delta doppler factor linear 16 | K particle density [cm^-3] log 17 | n1 n_1 (first index) linear 18 | n2 n_2 (second index) linear 19 | gamma_min low-energy cutoff log 20 | gamma_max high-energy cutoff log 21 | gamma_break energy break log 22 | B magnetic field strength [G] log 23 | R blob radius (cm) log 24 | =================== ============================= ====== 25 | 26 | """ 27 | import datetime 28 | import multiprocessing 29 | import os 30 | import sys 31 | import platform 32 | import shutil 33 | import numpy as np 34 | import emcee 35 | 36 | from bjet_mcmc import blazar_model 37 | from bjet_mcmc import blazar_report 38 | from bjet_mcmc import blazar_utils 39 | from bjet_mcmc import blazar_clean 40 | from bjet_mcmc import blazar_initialize 41 | 42 | from bjet_mcmc.blazar_properties import * 43 | 44 | __all__ = ["run_mcmc", "mcmc"] 45 | 46 | 47 | def run_mcmc( 48 | configs, 49 | param_min_vals=None, 50 | param_max_vals=None, 51 | backend_file=RESULTS_FOLDER + "/backend.h5", 52 | p0=None, 53 | p0_file=None, 54 | eic_p0_from_std=False, 55 | min_freq=None, 56 | max_freq=None, 57 | prev_files=False, 58 | use_param_file=True, 59 | eic=False, 60 | ): 61 | """ 62 | This function runs an MCMC simulation using the emcee package. 63 | 64 | Config dictionary keys and values: 65 | Keys are strings, value format is mixed 66 | 67 | ================= =================================================== 68 | Key (str) Value 69 | ================= =================================================== 70 | data_file (str) relative path to data 71 | n_steps (int) number of num to run 72 | n_walkers (int) number of walkers 73 | discard (int) how many num are discarded before analysis 74 | parallel (bool) whether parallel processing will be used 75 | cores (int) NOT PRESENT IF PARALLEL IS FALSE; # of cores 76 | if absent and parallel TRUE, 77 | (# cores on machine - 1) used 78 | tau_variability (float) time in hours for variability constraint 79 | ================= =================================================== 80 | 81 | 82 | :param configs: keys are strings, value types are mixed Configurations usually obtained with read_configs. See below for necessary dictionary elements. 83 | :type configs: dict 84 | :param param_min_vals: A numpy array (NUM_DIM,) of the minimum values for each parameter. If None, default values will be used. 85 | :type param_min_vals: numpy array, optional 86 | :param param_max_vals: A numpy array (NUM_DIM,) of the maximum values for each parameter. If None, default values will be used. 87 | :type param_max_vals: numpy array, optional 88 | :param backend_file: The file name of the backend HDF5 file. Default is 'backend.h5'. 89 | :type backend_file: str, optional 90 | :param p0: 2D np array of floats, shape (n_walkers, NUM_DIM) initial locations. Default is none; then, random start parameters will be used. Usually only specify this if you would like to continue a previous run from the last state of a chain. The starting positions for the walkers. If None, random positions will be generated. If eic_p0_from_std is True, these positions will be used to generate the starting positions. Otherwise, if p0_file is provided, positions from this file will be used. If p0 is provided, these positions will be used. Else, random positions will be generated based on the parameter limits. 91 | :type p0: numpy array, optional 92 | :param p0_file: The file name of the HDF5 file containing the starting positions for the walkers. If provided, the positions from this file will be used. If not, random positions will be generated. 93 | :type p0_file: str, optional 94 | :param eic_p0_from_std: If True, starting positions will be generated based on the standard deviation of the parameters specified in p0_file. This option is only valid for EIC mode. Default is False. 95 | :type eic_p0_from_std: bool, optional 96 | :param min_freq: The minimum frequency to be considered in the blazar SED model. If None, the minimum frequency in the data file will be used. 97 | :type min_freq: float, optional 98 | :param max_freq: The maximum frequency to be considered in the blazar SED model. If None, the maximum frequency in the data file will be used. 99 | :type max_freq: float, optional 100 | :param prev_files: If True, previous output files will be read and used as additional data points. Default is False. 101 | :type prev_files: bool, optional 102 | :param use_param_file: If True, the param_file will be used to store the walker positions. Default is True. 103 | :type use_param_file: bool, optional 104 | :param eic: If True, the model will be run in EIC mode. Otherwise, non-EIC mode will be used. Default is False. 105 | :type eic: bool, optional 106 | :return: The sampler object containing information about the MCMC run, and the duration of the run as a string (string of how long the MCMC took in hh:mm:ss.ssssss). 107 | :rtype: tuple(emcee.EnsembleSampler, time) 108 | """ 109 | if configs["parallel"]: 110 | if "cores" not in configs: 111 | pool = multiprocessing.Pool() 112 | else: 113 | pool = multiprocessing.Pool(processes=configs["cores"]) 114 | else: 115 | pool = None 116 | backend = emcee.backends.HDFBackend(BASE_PATH + backend_file) 117 | backend.reset( 118 | configs["n_walkers"], 119 | modelProperties(eic, fixed_params=configs["fixed_params"]).NUM_DIM, 120 | ) 121 | # set minima and maxima for the parameter values 122 | 123 | if param_min_vals is None or param_max_vals is None: 124 | default_min_max = blazar_utils.min_max_parameters( 125 | alpha2_limits=configs["alpha2_limits"], 126 | eic=eic, 127 | fixed_params=configs["fixed_params"], 128 | ) 129 | if param_min_vals is None: 130 | param_min_vals = default_min_max[0] 131 | if param_max_vals is None: 132 | param_max_vals = default_min_max[1] 133 | 134 | bjet_command_1, bjet_command_2 = blazar_model.command_line_sub_strings( 135 | min_freq=min_freq, 136 | max_freq=max_freq, 137 | prev_files=prev_files, 138 | redshift=configs["redshift"], 139 | eic=eic, 140 | ) 141 | # read data 142 | v_data, vFv_data, err_data = blazar_utils.read_data(configs["data_file"]) 143 | 144 | # starting position, a numpy array with # of walkers rows and # of parameters columns 145 | if eic_p0_from_std: 146 | if p0_file is None and p0 is None: 147 | raise ValueError("eic_p0_from_std is True but no p0 source provided") 148 | if not eic: 149 | raise ValueError("eic_p0_from_std is True, but mode is not EIC") 150 | if p0_file is not None: 151 | reader = emcee.backends.HDFBackend(BASE_PATH + p0_file, read_only=True) 152 | p0 = reader.get_last_sample().coords 153 | p0 = blazar_utils.random_eic_from_std( 154 | p0, 155 | configs["n_walkers"], 156 | param_min_vals, 157 | param_max_vals, 158 | redshift=configs["redshift"], 159 | tau_var=configs["tau_variability"], 160 | use_variability=configs["use_variability"], 161 | ) 162 | print("p0 eic from std") 163 | elif p0_file is not None: 164 | reader = emcee.backends.HDFBackend(BASE_PATH + p0_file, read_only=True) 165 | p0 = reader.get_last_sample() 166 | if len(p0.coords) != configs["n_walkers"]: 167 | raise ValueError( 168 | "p0 start has the incorrect number of walkers. p0 has " 169 | + str(len(p0.coords)) 170 | + " but the number of walkers is " 171 | + configs["n_walkers"] 172 | + "." 173 | ) 174 | if configs["eic"] and len(p0.coords[0]) != 13: 175 | raise ValueError( 176 | "for an EIC run, p0 coordinates must have 13 values. " 177 | + str(len(p0.coords[0])) 178 | + " values present." 179 | ) 180 | elif not configs["eic"] and len(p0.coords[0]) != 9: 181 | raise ValueError( 182 | "for a non-EIC run, p0 coordinates must have 9 values. " 183 | + str(len(p0.coords[0])) 184 | + " values present." 185 | ) 186 | print("p0 from file") 187 | elif p0 is not None: 188 | if len(p0) != configs["n_walkers"]: 189 | raise ValueError( 190 | "p0 start has the incorrect number of walkers. p0 has " 191 | + str(len(p0.coords)) 192 | + " but the number of walkers is " 193 | + configs["n_walkers"] 194 | + "." 195 | ) 196 | if configs["eic"] and len(p0[0]) != 13: 197 | raise ValueError( 198 | "for an EIC run, p0 coordinates must have 13 values. " 199 | + str(len(p0[0])) 200 | + " values present." 201 | ) 202 | elif not configs["eic"] and len(p0[0]) != 9: 203 | raise ValueError( 204 | "for a non-EIC run, p0 coordinates must have 9 values. " 205 | + str(len(p0[0])) 206 | + " values present." 207 | ) 208 | print("p0 from values") 209 | else: 210 | p0 = blazar_utils.random_defaults( 211 | configs["n_walkers"], 212 | param_min_vals, 213 | param_max_vals, 214 | redshift=configs["redshift"], 215 | tau_var=configs["tau_variability"], 216 | use_variability=configs["use_variability"], 217 | eic=eic, 218 | fixed_params=configs["fixed_params"], 219 | ) 220 | print("p0 from random") 221 | for i in range(len(configs["fixed_params"])): 222 | if configs["fixed_params"][i] != -np.inf and configs["eic"]: 223 | print(EIC_PARAM_NAMES[i], "is fixed at", configs["fixed_params"][i]) 224 | elif configs["fixed_params"][i] != -np.inf: 225 | print(SSC_PARAM_NAMES[i], "is fixed at", configs["fixed_params"][i]) 226 | # create sampler 227 | sampler = emcee.EnsembleSampler( 228 | configs["n_walkers"], 229 | modelProperties(eic, fixed_params=configs["fixed_params"]).NUM_DIM, 230 | blazar_utils.log_probability, 231 | args=[v_data, vFv_data, err_data], 232 | kwargs={ 233 | "param_min_vals": param_min_vals, 234 | "param_max_vals": param_max_vals, 235 | "unique_name": True, 236 | "tau_var": configs["tau_variability"], 237 | "use_variability": configs["use_variability"], 238 | "redshift": configs["redshift"], 239 | "min_freq": min_freq, 240 | "max_freq": max_freq, 241 | "prev_files": prev_files, 242 | "use_param_file": use_param_file, 243 | "command_params_1": bjet_command_1, 244 | "command_params_2": bjet_command_2, 245 | "torus_temp": None, 246 | "torus_luminosity": None, 247 | "torus_frac": None, 248 | "eic": eic, 249 | "fixed_params": configs["fixed_params"], 250 | }, 251 | backend=backend, 252 | moves=[(emcee.moves.StretchMove(a=2, live_dangerously=True), 1.0)], 253 | pool=pool, 254 | ) 255 | 256 | # moves set up by default moves=[(emcee.moves.StretchMove(live_dangerously=True), 1.)] 257 | # can try different moves to better probe the parameter space, but no real improvement so far after several tries 258 | # https://emcee.readthedocs.io/en/stable/user/moves/#moves-user 259 | 260 | # make pre-run txt file with basic info 261 | print("starting mcmc") 262 | start = datetime.datetime.now() 263 | sampler.run_mcmc(p0, configs["n_steps"], progress=True) 264 | end = datetime.datetime.now() 265 | if configs["parallel"]: 266 | pool.close() 267 | 268 | return sampler, str(end - start) 269 | 270 | 271 | def mcmc( 272 | config_file=None, 273 | directory=None, 274 | folder_label=None, 275 | p0=None, 276 | p0_label=None, 277 | p0_file=None, 278 | eic_p0_from_std=False, 279 | description=None, 280 | prev_files=False, 281 | use_param_file=False, 282 | ): 283 | """ 284 | The MCMC function that will run just given a configuration file--this is the function called by the main method. 285 | 286 | :param config_file: Absolute path to configuration file; default is None; if none, it will be set to "mcmc_config.txt" 287 | :type config_file: str 288 | :param directory: Location for results; default is none; if none, it will be in /run_YYYY-mm-dd-hh:mm:ss. This will be set with configs if possible. 289 | :type directory: str 290 | :param folder_label: If directory is None and folder_label is not None, results will be saved in a folder named `_YYYY-mm-dd-hh:mm:ss` 291 | :type folder_label: str 292 | :param p0: numpy arr of floats, n_walkers x NUM_DIM). Initial positions of the walkers; default is None; if none, random positions will be used. Usually only set this if continuing a run from a past MCMC run. 293 | :type p0: list or None 294 | :param p0_label: The label for the initial parameter values. 295 | :type p0_label: str 296 | :param p0_file: Label describing where the p0 values came from; default is none; if none, the label will be "random" 297 | :type p0_file: str or None 298 | :param eic_p0_from_std: A flag indicating whether to use EIC p0 values from standard deviations. 299 | :type eic_p0_from_std: bool 300 | :param description: A description of the MCMC analysis. 301 | :type description: str or None 302 | :param prev_files: A flag indicating whether to use previous files. 303 | :type prev_files: bool 304 | :param use_param_file: A flag indicating whether to use a parameter file. 305 | :type use_param_file: bool 306 | :return: The MCMC sampler and the directory where the results are saved. 307 | :rtype: tuple 308 | """ 309 | configs = blazar_utils.read_configs(config_file=config_file) 310 | 311 | if description is None and "description" in configs: 312 | description = configs["description"] 313 | 314 | if description is not None: 315 | print(description) 316 | 317 | if folder_label is None and "folder_label" in configs: 318 | folder_label = configs["folder_label"] 319 | data = blazar_utils.read_data(configs["data_file"]) 320 | param_min_vals, param_max_vals = blazar_utils.min_max_parameters( 321 | alpha2_limits=configs["alpha2_limits"], 322 | eic=configs["eic"], 323 | fixed_params=configs["fixed_params"], 324 | ) 325 | 326 | # file is a folder with the data 327 | if directory is None: 328 | now = datetime.datetime.now() 329 | date_string = now.strftime("%Y-%m-%d-%H:%M:%S") 330 | if folder_label is None: 331 | folder_label = "run" 332 | directory = RESULTS_FOLDER + "/" + folder_label + "_" + date_string 333 | os.mkdir(BASE_PATH + directory) 334 | 335 | backend = directory + "/backend.h5" 336 | 337 | if p0_label is None: 338 | if p0_file is not None: 339 | p0_label = p0_file 340 | elif p0 is not None: 341 | p0_label = "from given values" 342 | else: 343 | p0_label = "random" 344 | if eic_p0_from_std: 345 | p0_label = "eic_p0_from_std " + p0_label 346 | 347 | # make file with basic info 348 | with open(BASE_PATH + directory + "/basic_info.txt", "w") as f: 349 | f.write("folder name: ") 350 | f.write(directory) 351 | if description is not None: 352 | f.write("\nreport description: ") 353 | f.write(description) 354 | f.write("\n") 355 | 356 | f.write("\nconfig file: ") 357 | if config_file == None: 358 | f.write("mcmc_config.txt") 359 | else: 360 | f.write(config_file) 361 | f.write("\nprev_files: ") 362 | f.write(str(prev_files)) 363 | f.write(", use_param_file: ") 364 | f.write(str(use_param_file)) 365 | f.write("\n\n") 366 | f.write("configurations:\n") 367 | f.write(str(configs)) 368 | f.write("\n\np0: ") 369 | f.write(p0_label) 370 | f.write("\n") 371 | 372 | results = run_mcmc( 373 | configs, 374 | param_min_vals=param_min_vals, 375 | param_max_vals=param_max_vals, 376 | backend_file=backend, 377 | p0=p0, 378 | p0_file=p0_file, 379 | eic_p0_from_std=eic_p0_from_std, 380 | prev_files=prev_files, 381 | use_param_file=use_param_file, 382 | eic=configs["eic"], 383 | ) 384 | 385 | with open(BASE_PATH + directory + "/basic_info.txt", "a") as f: 386 | f.write("\ntime: ") 387 | f.write(str(results[1])) 388 | f.write("\n") 389 | 390 | sampler = results[0] 391 | 392 | blazar_report.show_results(sampler, results[1], configs=configs) 393 | 394 | blazar_report.save_plots_and_info( 395 | configs, 396 | data, 397 | param_min_vals, 398 | param_max_vals, 399 | folder=directory, 400 | sampler=sampler, 401 | use_sampler=True, 402 | description=description, 403 | time=results[1], 404 | p0_source=p0_label, 405 | redshift=configs["redshift"], 406 | eic=configs["eic"], 407 | ) 408 | 409 | return sampler, directory 410 | 411 | 412 | def main_cli(): 413 | """ 414 | Calling blazar_run_mcmc.py without argument will run mcmc using the configurations in mcmc_config.txt 415 | To run it with a specific configuration file, the absolute path can be given as first argument 416 | e.g. $ python blazar_run_mcmc.py /home/my_configfile.txt 417 | and save data to RESULTS_FOLDER/run_yyyy-mm-dd-hh:mm:ss. 418 | """ 419 | if INITIALIZE: 420 | blazar_clean.clean() 421 | blazar_initialize.initialize() 422 | 423 | if len(sys.argv) > 1: 424 | config_file = sys.argv[1] 425 | else: 426 | config_file = None 427 | 428 | # label_p0 = "From local_results/3C66A_b5_no_eic_2022-07-20-19:42:07/backend.h5" 429 | label_p0 = None 430 | p0_values = None 431 | 432 | # file_p0 = "local_results/TON_599_no_eic/backend.h5" 433 | file_p0 = None 434 | p0_eic_from_std = False 435 | sampler_result, results_directory = mcmc( 436 | config_file=config_file, 437 | use_param_file=False, 438 | p0_label=label_p0, 439 | p0=p0_values, 440 | p0_file=file_p0, 441 | eic_p0_from_std=p0_eic_from_std, 442 | ) 443 | 444 | # in case of interrupted process, there may be leftovers in DATA_FOLDER, remove them 445 | ## NOTE: These are commented out by default because they interfere with 446 | # running multiple instances of Bjet at the same time, at least on 447 | # the ucsc hummingbird cluster 448 | # os.chdir(FOLDER_PATH + DATA_FOLDER) 449 | # files = [f for f in os.listdir() if f.startswith("run")] 450 | # for f in files: 451 | # os.remove(f) 452 | 453 | if TMP: 454 | shutil.move(BASE_PATH + results_directory, FOLDER_PATH + results_directory) 455 | shutil.rmtree(TEMP_DIR) 456 | 457 | 458 | if __name__ == "__main__": 459 | main_cli() 460 | -------------------------------------------------------------------------------- /bjet_mcmc/blazar_model.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | """ 4 | file name: blazar_model.py 5 | Contains functions to interact with the C++ code to create the SED models. In 6 | separate functions, it creates the necessary parameter file, calls the C++ code, 7 | reads the data saved by the C++ code, and processes the model data into a 8 | usable format. 9 | 10 | Then, the function ``make_model`` does all of this when called with parameters, which is 11 | the function that is used by the rest of the code. 12 | 13 | .. note:: 14 | All file paths are relative to blazars-mcmc 15 | 16 | Parameters are always listed in the following order: 17 | ``[delta, K, n1, n2, gamma_min, gamma_max, gamma_break, B, R]`` 18 | 19 | The additional parameters for EIC are ``bb_temp, l_nuc, tau, blob_dist``, in that order. 20 | All parameters are the logarithm of the true value except for delta, n1, and n2. 21 | 22 | .. list-table:: 23 | :header-rows: 1 24 | 25 | * - Parameter 26 | - Description 27 | - Scale 28 | * - ``delta`` 29 | - Doppler factor 30 | - Linear 31 | * - ``K`` 32 | - Particle density [cm^-3] 33 | - Log 34 | * - ``n1`` 35 | - alpha_1 (first index) 36 | - Linear 37 | * - ``n2`` 38 | - alpha_2 (second index) 39 | - Linear 40 | * - ``gamma_min`` 41 | - Low-energy cutoff 42 | - Log 43 | * - ``gamma_max`` 44 | - High-energy cutoff 45 | - Log 46 | * - ``gamma_break`` 47 | - Energy break 48 | - Log 49 | * - ``B`` 50 | - Magnetic field strength [G] 51 | - Log 52 | * - ``R`` 53 | - Blob radius [cm] 54 | - Log 55 | 56 | Additional params for EIC 57 | 58 | .. list-table:: 59 | :header-rows: 1 60 | 61 | * - Parameter 62 | - Description 63 | - Scale 64 | * - ``bb_temp`` 65 | - Black body temp of disk [K] 66 | - Log 67 | * - ``l_nuc`` 68 | - Nucleus luminosity [ergs/s] 69 | - Log 70 | * - ``tau`` 71 | - Fraction of luminosity scattered 72 | - Log 73 | * - ``blob_dist`` 74 | - Distance of blob [cm] 75 | - Log 76 | 77 | """ 78 | import os 79 | import subprocess 80 | 81 | import numpy as np 82 | from scipy import interpolate 83 | 84 | from bjet_mcmc.blazar_properties import * 85 | from bjet_core import bj_core 86 | 87 | __all__ = [ 88 | "add_data", 89 | "command_line_sub_strings", 90 | "create_params_file", 91 | "file_make_SED", 92 | "make_model", 93 | "make_SED", 94 | "params_linear_to_log", 95 | "params_log_to_linear", 96 | "process_model", 97 | ] 98 | 99 | 100 | def make_SED( 101 | params, 102 | name_stem=None, 103 | theta=None, 104 | redshift=None, 105 | min_freq=None, 106 | max_freq=None, 107 | torus_temp=None, 108 | torus_luminosity=None, 109 | torus_frac=None, 110 | data_folder=None, 111 | executable=None, 112 | command_params_full=None, 113 | command_params_1=None, 114 | command_params_2=None, 115 | prev_files=False, 116 | verbose=False, 117 | eic=False, 118 | folder=None, 119 | ): 120 | """ 121 | :param params: 1D numpy array of NUM_DIM floats 122 | :type params: numpy.ndarray 123 | :param name_stem: Name stem for make_model. Default is None; will then be set to default. 124 | :type name_stem: str, optional 125 | :param theta: Angle from the line of sight. Default is None, and it will be set to the default value of 0.57. 126 | :type theta: float, optional 127 | :param redshift: Redshift value; default is None, so the log_prior function will use the default, which is 0.143 (the value for J1010). 128 | :type redshift: float, optional 129 | :param min_freq: Minimum frequency for the SED model. Default is None, where it will be set to the default value of 5.0e+7 in blazar_model.process_model. 130 | :type min_freq: float, optional 131 | :param max_freq: Maximum frequency for the SED model. Default is None, where it will be set to the default value of 1.0e+29 in blazar_model.process_model. 132 | :type max_freq: float, optional 133 | :param torus_temp: Value for the torus temperature. Default is None, and it will be set to the default of 2.0e+4. 134 | :type torus_temp: float, optional 135 | :param torus_luminosity: Value for the torus luminosity. Default is None, and it will be set to the default of 5.5e+20. 136 | :type torus_luminosity: float, optional 137 | :param torus_frac: Value for the fraction of the torus luminosity reprocessed isotropically. Default is None, and it will be set to the default of 9.0e-5. 138 | :type torus_frac: float, optional 139 | :param data_folder: Relative path to the folder where data will be saved to. 140 | :type data_folder: str, optional 141 | :param executable: Where the bjet executable is located. 142 | :type executable: str, optional 143 | :param command_params_full: Full set of parameters to pass to the bjet exec--see the README for information. Should be length 22, 23, 28, or 29. 144 | :type command_params_full: numpy.ndarray, optional 145 | :param command_params_1: The settings and transformation parameters: [prev files flag, data folder, model type, redshift, hubble constant, theta]. 146 | :type command_params_1: numpy.ndarray, optional 147 | :param command_params_2: The constant and numerical parameters: [length of the emitting region, absorption by EBL, blob distance, # of spectral points, min freq, max freq, file name prefix]. 148 | :type command_params_2: numpy.ndarray, optional 149 | :param prev_files: Whether bjet should create _prev files after each run; default is False. 150 | :type prev_files: bool, optional 151 | :param verbose: Whether information on the model should be displayed; default is False. 152 | :type verbose: bool, optional 153 | :param eic: States whether the run is eic or std; default is False (std). 154 | :type eic: bool 155 | :param folder: Additional folder information; default is None. 156 | :type folder: str, optional 157 | """ 158 | # TODO rewrite this entire method using bj_core methods and without building a command string. 159 | if executable is None: 160 | executable = CPP_FOLDER + "/" + EXECUTABLE 161 | 162 | if command_params_full is None: 163 | params = params_log_to_linear( 164 | params, param_is_log=modelProperties(eic).PARAM_IS_LOG 165 | ) 166 | # if substrings are not provided 167 | if command_params_1 is None or command_params_2 is None: 168 | command_params_1, command_params_2 = command_line_sub_strings( 169 | name_stem=name_stem, 170 | theta=theta, 171 | redshift=redshift, 172 | min_freq=min_freq, 173 | max_freq=max_freq, 174 | data_folder=data_folder, 175 | prev_files=prev_files, 176 | eic=eic, 177 | ) 178 | # now create the params from the substrings 179 | if not eic: 180 | command_params_full = ( 181 | command_params_1 + [str(val) for val in params] + command_params_2 182 | ) 183 | else: 184 | if torus_temp is None: 185 | torus_temp = "2.0e+4" 186 | else: 187 | torus_temp = str(torus_temp) 188 | if torus_luminosity is None: 189 | torus_luminosity = "5.5e+20" 190 | else: 191 | torus_luminosity = str(torus_luminosity) 192 | if torus_frac is None: 193 | torus_frac = "9.0e-5" 194 | else: 195 | torus_frac = str(torus_frac) 196 | 197 | # this gives you the settings commands (command_params_1), the initial 9 parameters + length of emitting region (spherical) + absorption by EBL = yes, blob distance 198 | command_params_full = ( 199 | command_params_1 200 | + [str(val) for val in params[:9]] 201 | + command_params_2[:2] 202 | + [str(params[-1])] 203 | ) 204 | # add eic parameter values 205 | command_params_full = command_params_full + [ 206 | str(params[9]), 207 | torus_temp, 208 | str(params[10]), 209 | str(params[11]), 210 | torus_luminosity, 211 | torus_frac, 212 | ] 213 | 214 | # add numerical params (min/max freq, number of pts) 215 | command_params_full = command_params_full + command_params_2[3:] 216 | 217 | # command_params_full have been set now 218 | 219 | if not verbose: 220 | subprocess.run( 221 | [BASE_PATH + executable, *command_params_full], 222 | stderr=open(os.devnull, "wb"), 223 | stdout=open(os.devnull, "wb"), 224 | ) 225 | else: 226 | result = subprocess.run( 227 | [BASE_PATH + executable, *command_params_full], 228 | capture_output=True, 229 | text=True, 230 | ) 231 | print("params", params) 232 | print(command_params_full) 233 | 234 | # write log file and print 235 | print(result.stderr) 236 | with open(FOLDER_PATH + folder + "/bjet.log", "w") as f: 237 | f.write(result.stderr) 238 | 239 | 240 | def file_make_SED( 241 | parameter_file=None, 242 | data_folder=None, 243 | executable=None, 244 | prev_files=False, 245 | verbose=False, 246 | ): 247 | """ 248 | Calls the C++ code to generate the SED. 249 | Compton model data is saved to /DATA_FOLDER/_cs.dat 250 | Sync model data is saved to /DATA_FOLDER/_ss.dat 251 | 252 | :param parameter_file: Relative path to param file, will be overwritten with parameters; default is /params.txt. 253 | :type parameter_file: str 254 | :param data_folder: The path to the data folder. Default is None. 255 | :type data_folder: str 256 | :param executable: The path to the executable file. Default is None. 257 | :type executable: str 258 | :param prev_files: Flag indicating whether to create previous files. Default is False. 259 | :type prev_files: bool 260 | :param verbose: Flag indicating whether to display verbose output. Default is False. 261 | :type verbose: bool 262 | :return: None 263 | :rtype: None 264 | 265 | This function generates a system energy dissipation (SED) file by calling a C++ code. The SED file is stored in the /DATA_FOLDER with a given file name prefix. Data saved to /DATA_FOLDER/_*.dat. Parameter file overwritten or created. 266 | 267 | If the parameter_file is not provided, it will default to the "params.txt" file in the PARAMETER_FOLDER. 268 | If the data_folder is not provided, it will default to the DATA_FOLDER. 269 | If the executable is not provided, it will default to the EXECUTABLE file in the CPP_FOLDER. 270 | 271 | If prev_files is True, the C++ code is called with a "2" input mode. If prev_files is False, the C++ code is called with a "3" input mode. 272 | 273 | If verbose is True, the C++ code is called with verbose output. If verbose is False, the C++ code is called without displaying the output. 274 | 275 | .. note:: This method uses older implementation and it is recommended to rewrite the method using bj_core methods, avoiding building a command string. 276 | """ 277 | # TODO rewrite this entire method using bj_core methods and without building a command string. 278 | if parameter_file is None: 279 | parameter_file = PARAMETER_FOLDER + "/params.txt" 280 | if executable is None: 281 | executable = CPP_FOLDER + "/" + EXECUTABLE 282 | if data_folder is None: 283 | data_folder = DATA_FOLDER 284 | 285 | # Call C++ code to make the SED and 286 | # store it in /DATA_FOLDER with given file name prefix 287 | if prev_files: 288 | p = "2" 289 | else: 290 | p = "3" 291 | # input mode, data file 292 | settings_params = [p, BASE_PATH + data_folder] 293 | if verbose: 294 | subprocess.run( 295 | [BASE_PATH + executable, *settings_params, BASE_PATH + parameter_file] 296 | ) 297 | else: 298 | subprocess.run( 299 | [BASE_PATH + executable, *settings_params, BASE_PATH + parameter_file], 300 | stderr=open(os.devnull, "wb"), 301 | stdout=open(os.devnull, "wb"), 302 | ) 303 | 304 | 305 | def add_data( 306 | current_data, 307 | new_data=None, 308 | file_suffix=None, 309 | name_stem=None, 310 | data_folder=None, 311 | cols=(0, 2), 312 | ): 313 | """ 314 | Add new data to the current data. 315 | 316 | :raises IOError: If the specified data file cannot be read. 317 | :raises ValueError: If neither new data nor file suffix is provided. 318 | 319 | :param current_data: Tuple containing current data of the format (current_logv, current_logvFv, current_v, current_vFv). 320 | :type current_data: tuple 321 | :param new_data: Optional. Tuple containing new data to be added of the format (model_logv, model_logvFv, model_v, model_vFv). 322 | :type new_data: tuple 323 | :param file_suffix: Optional. String representing the file suffix for loading model data. 324 | :type file_suffix: str 325 | :param name_stem: Optional. String representing the name stem for the model data file. 326 | :type name_stem: str 327 | :param data_folder: Optional. String representing the folder path for the model data file to load. 328 | :type data_folder: str 329 | :param cols: Optional. Tuple representing the column indices to extract from the loaded data. Defaults to (0, 2). 330 | :type cols: tuple 331 | :return: Tuple containing the interpolated data of the format (logv, logvFv, v, vFv). 332 | :rtype: tuple 333 | """ 334 | if name_stem is None: 335 | name_stem = NAME_STEM 336 | if data_folder is None: 337 | data_folder = DATA_FOLDER 338 | 339 | current_logv, current_logvFv, current_v, current_vFv = current_data 340 | if new_data is not None: 341 | model_logv, model_logvFv, model_v, model_vFv = new_data 342 | elif file_suffix is not None: 343 | try: 344 | model_data = np.loadtxt( 345 | BASE_PATH + data_folder + "/" + name_stem + "_" + file_suffix + ".dat", 346 | delimiter=" ", 347 | ) 348 | except IOError: 349 | raise IOError( 350 | "add_data: " 351 | + BASE_PATH 352 | + data_folder 353 | + "/" 354 | + name_stem 355 | + "_" 356 | + file_suffix 357 | + ".dat cannot be read" 358 | ) 359 | 360 | if name_stem == "F_jet": 361 | model_logv = model_data[:, 3] 362 | model_logvFv = model_data[:, 5] 363 | model_vFv = model_data[:, 2] 364 | else: 365 | model_logv = model_data[:, cols[0]] 366 | model_logvFv = model_data[:, cols[1]] 367 | model_vFv = np.power(10, model_logvFv) 368 | else: 369 | raise ValueError("In add_data, data or file suffix not provided") 370 | 371 | """ 372 | Find overlap 373 | """ 374 | new_lower = np.where(model_logv < current_logv[0])[0] 375 | new_higher = np.where(model_logv > current_logv[-1])[0] 376 | 377 | logv = np.concatenate((model_logv[new_lower], current_logv, model_logv[new_higher])) 378 | logvFv = np.concatenate( 379 | (model_logvFv[new_lower], current_logvFv, model_logvFv[new_higher]) 380 | ) 381 | vFv = np.power(10, logvFv) 382 | 383 | overlap_start = np.where(logv >= max(model_logv[0], current_logv[0]))[0][0] 384 | overlap_end = np.where(logv <= min(model_logv[-1], current_logv[-1]))[0][-1] 385 | 386 | interpolation = interpolate.interp1d(model_logv, model_vFv) 387 | 388 | new_vFv = np.concatenate( 389 | ( 390 | np.zeros(overlap_start), 391 | interpolation(logv[overlap_start : overlap_end + 1]), 392 | np.zeros(len(logv) - overlap_end - 1), 393 | ) 394 | ) 395 | 396 | vFv = vFv + new_vFv 397 | logvFv = np.log10(vFv) 398 | v = np.power(10, logv) 399 | return logv, logvFv, v, vFv 400 | 401 | 402 | def process_model( 403 | name_stem=None, data_folder=None, verbose=False, eic=False, additional_suffixes=None 404 | ): 405 | """ 406 | Read a model from data files and returns arrays of frequencies and energy flux. 407 | This model only uses data from the *compton model* and the *synchrotron model*. 408 | The data we want are an array of frequencies (v) and an array of corresponding flux energies (vFv). Flux energy is the sum of the flux energy from the synchrotron model and that from the compton model when there are data points for both of them. 409 | 410 | .. warning:: 411 | Requirements: 412 | - The SED model must have already been created (using `make_SED above`) with the given name_stem. 413 | - By default, data is read from `DATA_FOLDER/_*.dat`, the location that make_SED writes to. 414 | 415 | Returns: 416 | - a tuple of 4 1D numpy arrays 417 | - all arrays have the same length. 418 | - logv_all, logvFv_all, v_all, vFv_all 419 | - logv_all: a 1D numpy array of the log of all frequencies 420 | - logvFv_all: a 1D numpy array of the log of all the energy flux 421 | - v_all: a 1D numpy array of all frequencies in the data 422 | - vFv_all: a 1D numpy array of corresponding energy fluxes for the frequencies 423 | 424 | :raises IOError: when data cannot be read 425 | 426 | .. note:: The frequency values used are the ones used in the synchrotron spectrum and the ones in the compton model greater than the max in the synchrotron. The frequency values present in the Compton model in the overlap are not used. 427 | 428 | :param name_stem: The stem name that will be used to construct the file names of the models. If not provided, it will use the default value `NAME_STEM`. Model data is saved in files named in the form _*.dat, specify file name 429 | :type name_stem: str, optional 430 | 431 | :param data_folder: The folder where the model files are located. If not provided, it will use the default value `DATA_FOLDER`. 432 | :type data_folder: str, optional 433 | 434 | :param verbose: Determines whether to print additional information during the process. Default is `False`. 435 | :type verbose: bool, optional 436 | 437 | :param eic: Determines whether to enable Extended Inverse Compton (EIC) mode. Default is `False`. 438 | :type eic: bool, optional 439 | 440 | :param additional_suffixes: A list of additional suffixes to be used for reading data in EIC mode. Default is `None`. 441 | :type additional_suffixes: list, optional 442 | 443 | :return: Four numpy arrays representing the logarithm of frequency, logarithm of energy flux, frequency, and energy flux respectively. 444 | :rtype: tuple of numpy arrays 445 | 446 | """ 447 | 448 | if name_stem is None: 449 | name_stem = NAME_STEM 450 | if data_folder is None: 451 | data_folder = DATA_FOLDER 452 | # Read in models from the files created by the c++ code 453 | # This model uses only the data from the compton model and the synchrotron 454 | # model. 455 | # Data is read into a numpy 2D array 456 | try: 457 | synchrotron_model = np.loadtxt( 458 | BASE_PATH + data_folder + "/" + name_stem + "_ss.dat", delimiter=" " 459 | ) 460 | except IOError: 461 | raise IOError( 462 | "process_model: " 463 | + BASE_PATH 464 | + data_folder 465 | + "/" 466 | + name_stem 467 | + "_*.dat cannot be read" 468 | ) 469 | 470 | # extract data used - only use frequency and energy flux, which are the 1st 471 | # and 3rd columns 472 | logv_synchrotron = synchrotron_model[:, 0] 473 | logvFv_synchrotron = synchrotron_model[:, 2] 474 | v_synchrotron = np.power(10, logv_synchrotron) 475 | vFv_synchrotron = np.power(10, logvFv_synchrotron) 476 | 477 | logv, logvFv, v, vFv = add_data( 478 | (logv_synchrotron, logvFv_synchrotron, v_synchrotron, vFv_synchrotron), 479 | file_suffix="cs", 480 | name_stem=name_stem, 481 | data_folder=data_folder, 482 | ) 483 | logv, logvFv, v, vFv = add_data( 484 | (logv, logvFv, v, vFv), 485 | file_suffix="cs2", 486 | name_stem=name_stem, 487 | data_folder=data_folder, 488 | ) 489 | # Total energy flux is determined by summing the flux from the compton and 490 | # synchrotron models. 491 | 492 | if eic: 493 | if additional_suffixes is None: 494 | additional_suffixes = ["ecs", "nuc"] 495 | if verbose: 496 | print("process_model EIC mode: ss cs", *additional_suffixes, "read") 497 | for s in additional_suffixes: 498 | logv, logvFv, v, vFv = add_data( 499 | (logv, logvFv, v, vFv), 500 | file_suffix=s, 501 | name_stem=name_stem, 502 | data_folder=data_folder, 503 | ) 504 | elif verbose: 505 | print("process_model SSC mode") 506 | 507 | return logv, logvFv, v, vFv 508 | 509 | 510 | def make_model( 511 | params, 512 | name_stem=None, 513 | theta=None, 514 | redshift=None, 515 | min_freq=None, 516 | max_freq=None, 517 | torus_temp=None, 518 | torus_luminosity=None, 519 | torus_frac=None, 520 | data_folder=None, 521 | executable=None, 522 | command_params_full=None, 523 | command_params_1=None, 524 | command_params_2=None, 525 | parameter_file=None, 526 | prev_files=False, 527 | use_param_file=False, 528 | verbose=False, 529 | eic=False, 530 | fixed_params=None, 531 | folder=None, 532 | ): 533 | """ 534 | Given parameters, returns v and vFv for the corresponding model. 535 | 536 | Args: 537 | params (list of floats): a list of NUM_DIM floats which are the parameters 538 | name_stem (str): data will be saved in files of the form `_*.dat` 539 | parameter_file (str): optional; relative path of the parameter file 540 | theta: optional; params is fixed for modeling 541 | redshift: optional; redshift is fixed for modeling 542 | min_freq (float): optional; specifies min frequency model SEDs should use; default value used if none provided, which is 5.0e+7. 543 | max_freq (float): optional; specifies max frequency model SEDs should use; default value used if none provided, which is 1.0e+29. 544 | executable (str): optional; where the bjet executable is located 545 | data_folder (str): relative path to the folder where data will be saved to 546 | use_param_file (bool): specifies if bjet should be called with parameter file or with command line args 547 | verbose (bool): specifies if parameters and output of bjet should be shown 548 | 549 | After function call: parameter_files is over-written with parameter information. 550 | Files of the form _*.dat are created inside 551 | 552 | Returns: 553 | a tuple of 4 1D numpy arrays 554 | 555 | all arrays have the same length. 556 | logv_all, logvFv_all, v_all, vFv_all 557 | 558 | logv_all: a 1D numpy array of the log of all frequencies 559 | logvFv_all: a 1D numpy array of the log of all the energy flux 560 | v_all: a 1D numpy array of all frequencies in the data 561 | vFv_all: a 1D numpy array of corresponding energy fluxes for the frequencies 562 | 563 | :raises IOError: if parameter_files cannot be written to (likely, a folder in the path does not exist) 564 | 565 | :param params: The parameters for the model computation. A list of NUM_DIM floats which are the parameters 566 | :type params: numpy.ndarray 567 | :param name_stem: The stem name for the model files. 568 | :type name_stem: str 569 | :param theta: The angle parameter for the model computation. 570 | :type theta: float 571 | :param redshift: The redshift parameter for the model computation. 572 | :type redshift: float 573 | :param min_freq: The minimum frequency parameter for the model computation. 574 | :type min_freq: float 575 | :param max_freq: The maximum frequency parameter for the model computation. 576 | :type max_freq: float 577 | :param torus_temp: The temperature parameter for the torus component in the model computation. 578 | :type torus_temp: float 579 | :param torus_luminosity: The luminosity parameter for the torus component in the model computation. 580 | :type torus_luminosity: float 581 | :param torus_frac: The fraction parameter for the torus component in the model computation. 582 | :type torus_frac: float 583 | :param data_folder: The folder containing the data files. 584 | :type data_folder: str 585 | :param executable: The path to the executable file. 586 | :type executable: str 587 | :param command_params_full: Additional command line parameters for the model computation. 588 | :type command_params_full: str 589 | :param command_params_1: Additional command line parameters for the model computation. 590 | :type command_params_1: str 591 | :param command_params_2: Additional command line parameters for the model computation. 592 | :type command_params_2: str 593 | :param parameter_file: The path to the parameter file. 594 | :type parameter_file: str 595 | :param prev_files: Flag indicating whether to use previous files. 596 | :type prev_files: bool 597 | :param use_param_file: Flag indicating whether to use the parameter file. 598 | :type use_param_file: bool 599 | :param verbose: Flag indicating whether to display verbose output. 600 | :type verbose: bool 601 | :param eic: Flag indicating whether to use EIC mode. 602 | :type eic: bool 603 | :param fixed_params: The fixed parameters for the model computation. 604 | :type fixed_params: numpy.ndarray 605 | :param folder: The folder for the model files. 606 | :type folder: str 607 | :return: The computed model. 608 | :rtype: numpy.ndarray 609 | """ 610 | if use_param_file: 611 | if eic: 612 | raise ValueError("EIC mode cannot be used with parameter file") 613 | create_params_file( 614 | params, 615 | name_stem, 616 | parameter_file, 617 | theta=theta, 618 | redshift=redshift, 619 | min_freq=min_freq, 620 | max_freq=max_freq, 621 | verbose=verbose, 622 | ) 623 | # reimplement fixed parameters for the model computation 624 | if fixed_params: 625 | for i in range(len(fixed_params)): 626 | if fixed_params[i] != -np.inf: 627 | params = np.insert(params, i, fixed_params[i]) 628 | make_SED( 629 | params, 630 | name_stem=name_stem, 631 | theta=theta, 632 | redshift=redshift, 633 | min_freq=min_freq, 634 | max_freq=max_freq, 635 | torus_temp=torus_temp, 636 | torus_luminosity=torus_luminosity, 637 | torus_frac=torus_frac, 638 | data_folder=data_folder, 639 | executable=executable, 640 | command_params_full=command_params_full, 641 | command_params_1=command_params_1, 642 | command_params_2=command_params_2, 643 | prev_files=prev_files, 644 | verbose=verbose, 645 | eic=eic, 646 | folder=folder, 647 | ) 648 | return process_model(name_stem=name_stem, data_folder=data_folder, eic=eic) 649 | 650 | 651 | def command_line_sub_strings( 652 | name_stem=None, 653 | theta=None, 654 | redshift=None, 655 | min_freq=None, 656 | max_freq=None, 657 | data_folder=None, 658 | prev_files=False, 659 | eic=False, 660 | ): 661 | """ 662 | 663 | :param name_stem: The prefix for the file name. If not provided, it defaults to NAME_STEM. 664 | :type name_stem: str 665 | :param theta: The angle value. If not provided, it defaults to 0.57. 666 | :type theta: float 667 | :param redshift: The redshift value. 668 | :type redshift: float 669 | :param min_freq: The minimum frequency value. If not provided, it defaults to 1.0e08. 670 | :type min_freq: float 671 | :param max_freq: The maximum frequency value. If not provided, it defaults to 1.0e28. 672 | :type max_freq: float 673 | :param data_folder: The folder where the data files are located. If not provided, it defaults to DATA_FOLDER. 674 | :type data_folder: str 675 | :param prev_files: Flag indicating whether to use previous files. If set to True, it uses "2" as the value of p, otherwise it uses "3". 676 | :type prev_files: bool 677 | :param eic: Flag indicating the model type. If set to True, it uses "1" as the value of model_type, otherwise it uses "0". 678 | :type eic: bool 679 | :return: A tuple containing the settings and transformation values, and the constant and numerical values. 680 | :rtype: tuple, tuple 681 | """ 682 | if name_stem is None: 683 | name_stem = NAME_STEM 684 | if theta is None: 685 | theta = 0.57 686 | if redshift is None: 687 | print("here in command_line_sub_strings") 688 | pass 689 | if min_freq is None: 690 | min_freq = 1.0e08 691 | if max_freq is None: 692 | max_freq = 1.0e28 693 | if data_folder is None: 694 | data_folder = DATA_FOLDER 695 | if prev_files: 696 | p = "2" 697 | else: 698 | p = "3" 699 | 700 | # input type, data file, model specification, redshift, hubble const, angle 701 | if eic: 702 | model_type = "1" 703 | else: 704 | model_type = "0" 705 | settings_and_transformation = [ 706 | p, 707 | BASE_PATH + data_folder, 708 | model_type, 709 | str(redshift), 710 | "69.6", 711 | str(theta), 712 | ] 713 | 714 | # length of emitting region, absorption by EBL, distance of blob (host galaxy frame) 715 | # number of spectral points, minimal frequency, maximal frequency, file name prefix 716 | constant_and_numerical = [ 717 | "0", 718 | "1", 719 | "9.0e+17", 720 | "99", 721 | str(min_freq), 722 | str(max_freq), 723 | name_stem, 724 | ] 725 | return settings_and_transformation, constant_and_numerical 726 | 727 | 728 | def create_params_file( 729 | params, 730 | name_stem=None, 731 | parameter_file=None, 732 | theta=None, 733 | redshift=None, 734 | min_freq=None, 735 | max_freq=None, 736 | verbose=False, 737 | ): 738 | """ 739 | Given parameters and a file, put the data in the file in the format 740 | understandable by the C++ code. 741 | 742 | .. note:: Cannot be used with EIC 743 | 744 | :raises IOError: if parameter_files cannot be written to (likely, a folder in the path does not exist) 745 | 746 | :param params: List of parameters 747 | Form: [delta (linear), K (log), n1 (linear), n2 (linear), gamma_min (log), gamma_max (log), gamma_break (log), B (log), R (log)] 748 | :type params: list 749 | :param name_stem: Name stem of the output file. Data will be saved in files named _*.dat 750 | :type name_stem: str 751 | :param parameter_file: Output file name. String with the relative path of the parameter file; default is None; will be set to "/params.txt" 752 | :type parameter_file: str 753 | :param theta: Angle to the line of sight 754 | :type theta: float 755 | :param redshift: Redshift 756 | :type redshift: float 757 | :param min_freq: Minimal frequency. Specifies min frequency model SEDs should use; default is None; will be set to 5.0e+7 758 | :type min_freq: float 759 | :param max_freq: Maximal frequency. Specifies max frequency model SEDs should use; default is None; will be set to 1.0e+29 760 | :type max_freq: float 761 | :param verbose: Verbose output flag 762 | :type verbose: bool 763 | :return: None parameter_files is over-written (and createed if necessary) with parameter information. 764 | :rtype: None 765 | """ 766 | if parameter_file is None: 767 | parameter_file = PARAMETER_FOLDER + "/params.txt" 768 | if name_stem is None: 769 | name_stem = NAME_STEM 770 | if theta is None: 771 | theta = 0.57 772 | if redshift is None: 773 | redshift = 0.143 774 | if min_freq is None: 775 | min_freq = 5.0e7 776 | if max_freq is None: 777 | max_freq = 1.0e29 778 | if verbose: 779 | print(params) 780 | 781 | # Set parameters from list, convert those in log space to linear space 782 | ( 783 | doppler_param, 784 | K_param, 785 | n1_param, 786 | n2_param, 787 | gamma_min_param, 788 | gamma_max_param, 789 | gamma_break_param, 790 | B_param, 791 | R_param, 792 | ) = params_log_to_linear(params, eic=False) 793 | 794 | if verbose: 795 | print("z (fixed) =", redshift) 796 | print("params (fixed) =", theta) 797 | print("doppler =", doppler_param) 798 | print("K =", K_param) 799 | print("n1 =", n1_param) 800 | print("n2 =", n2_param) 801 | print("Gamma min =", gamma_min_param) 802 | print("Gamma max =", gamma_max_param) 803 | print("Gamma break =", gamma_break_param) 804 | print("B =", B_param) 805 | print("R =", R_param) 806 | 807 | # write data with the parameters in the format the C++ code can understand 808 | # into the given address for parameter_files 809 | try: 810 | with open(BASE_PATH + parameter_file, "w") as file: 811 | file.write( 812 | "------------------------------------------------------------------------------ \n" 813 | ) 814 | file.write("Transformation_parameters \n") 815 | file.write( 816 | "------------------------------------------------------------------------------ \n" 817 | ) 818 | file.write(str(redshift) + " redshift \n") 819 | file.write( 820 | "69.6 Hubble_constant______________________________________[km/(sMpc)] \n" 821 | ) 822 | file.write( 823 | str(theta) 824 | + " angle_to_the_line_of_sight___________________________[degrees] \n" 825 | ) 826 | file.write( 827 | "------------------------------------------------------------------------------ \n" 828 | ) 829 | file.write("Blob_parameters \n") 830 | file.write( 831 | "------------------------------------------------------------------------------ \n" 832 | ) 833 | file.write(str(doppler_param) + " Doppler_factor \n") 834 | file.write( 835 | str(K_param) 836 | + " Particle_density_____________________________________[1/cm^3] \n" 837 | ) 838 | file.write( 839 | str(n1_param) + " First_slope_of_particle_energy_spectrum \n" 840 | ) 841 | file.write( 842 | str(n2_param) 843 | + " Second_slope_of_particle_energy_spectrum \n" 844 | ) 845 | file.write(str(gamma_min_param) + " Minimum_electrons_energy \n") 846 | file.write(str(gamma_max_param) + " Maximum_electrons_energy \n") 847 | file.write( 848 | str(gamma_break_param) + " Break_in_electrons_energy_spectrum \n" 849 | ) 850 | file.write( 851 | str(B_param) 852 | + " Magnetic_field_______________________________________[G] \n" 853 | ) 854 | file.write( 855 | str(R_param) 856 | + " Radius_of_emitting_region____________________________[cm] \n" 857 | ) 858 | file.write( 859 | "0 length_of_emitting_region_(0_for_spherical_geometry)_[cm] \n" 860 | ) 861 | file.write("1 absorption_by_EBL_(0=NO___1=YES) \n") 862 | file.write( 863 | "9.0e+17 distance_blob_SMBH_(host_galaxy_frame)_______________[cm] \n" 864 | ) 865 | file.write( 866 | "------------------------------------------------------------------------------ \n" 867 | ) 868 | file.write("Extern_Inverse_Compton_parameter \n") 869 | file.write( 870 | "------------------------------------------------------------------------------ \n" 871 | ) 872 | file.write("0 compute_EIC_(0=NO___1=YES) \n") 873 | file.write("0 compute_X_corona_(0=NO___1=YES) \n") 874 | file.write( 875 | "4.0e+4 Disk_black_body_temperature__________________________[K] \n" 876 | ) 877 | file.write( 878 | "2.0e+4 Torus_black_body_temperature_________________________[K] \n" 879 | ) 880 | file.write( 881 | "3.0e+43 Luminosity_of_the_disk_______________________________[erg/s] \n" 882 | ) 883 | file.write( 884 | "9.0e-5 Tau___fraction_of_L_disk_reprocessed_isotropically \n" 885 | ) 886 | file.write( 887 | "5.5e+20 Luminosity_of_the_torus______________________________[erg/s] \n" 888 | ) 889 | file.write( 890 | "9.0e-5 Tau___fraction_of_L_tor_reprocessed_isotropically \n" 891 | ) 892 | file.write( 893 | "------------------------------------------------------------------------------ \n" 894 | ) 895 | file.write("Jet_parameters \n") 896 | file.write( 897 | "------------------------------------------------------------------------------ \n" 898 | ) 899 | file.write("0 compute_JET_(0=NO___1=YES) \n") 900 | file.write("3.0 Doppler_factor \n") 901 | file.write( 902 | "1.0e+2 Initial_particle_density_____________________________[1/cm^3] \n" 903 | ) 904 | file.write("2.1 Slope_of_particle_energy_spectrum \n") 905 | file.write("1.0e+3 Minimum_electrons_energy \n") 906 | file.write("2.0e+4 Maximum_electrons_energy \n") 907 | file.write( 908 | "0.08 Initial_magnetic_field_______________________________[G] \n" 909 | ) 910 | file.write( 911 | "1.2e+17 Inner_radius_(host_galaxy_frame)_____________________[cm] \n" 912 | ) 913 | file.write( 914 | "300 Jet_length_(host_galaxy_frame)_______________________[pc] \n" 915 | ) 916 | file.write( 917 | "1.0 Half-opening_angle_of_jet_(host_galaxy_frame)________[deg] \n" 918 | ) 919 | file.write("50 number_of_slices \n") 920 | file.write( 921 | "------------------------------------------------------------------------------ \n" 922 | ) 923 | file.write("Numerical_parameters \n") 924 | file.write( 925 | "------------------------------------------------------------------------------ \n" 926 | ) 927 | file.write("99 number_of_spectral_points \n") 928 | file.write( 929 | str(min_freq) 930 | + " minimal_frequency____________________________________[Hz] \n" 931 | ) 932 | file.write( 933 | str(max_freq) 934 | + " maximal_frequency____________________________________[Hz] \n" 935 | ) 936 | file.write(name_stem + " prefix_of_file_names \n") 937 | except IOError: 938 | raise IOError( 939 | "create_params_file: " + parameter_file + " could not be written to" 940 | ) 941 | 942 | 943 | def params_log_to_linear(params, param_is_log=None, eic=False): 944 | """ 945 | Converts parameters from logarithmic to linear scale. 946 | 947 | :param params: The parameters to be converted. 948 | :type params: list[float] 949 | :param param_is_log: A list indicating whether each parameter is in logarithmic scale. If None, it is determined by modelProperties. 950 | :type param_is_log: list[bool] 951 | :param eic: Whether to use EIC for determining logarithmic scale. Default is False. 952 | :type eic: bool 953 | :return: A new list of parameters converted from log scale to linear scale if necessary. 954 | :rtype: list[float] 955 | """ 956 | if param_is_log is None: 957 | param_is_log = modelProperties(eic).PARAM_IS_LOG 958 | 959 | ret = params.copy() 960 | for i in range(len(params)): 961 | if param_is_log[i]: 962 | ret[i] = np.power(10, params[i]) 963 | return ret 964 | 965 | 966 | def params_linear_to_log(params, param_is_log=None, eic=False): 967 | """ 968 | Converts linear scale parameters to logarithmic scale. 969 | 970 | .. note:: 971 | - If `param_is_log` is not provided, it will be inferred from the model properties based on `eic`. 972 | - The conversion to log scale is performed using the base 10 logarithm (np.log10). 973 | 974 | :param params: The linear scale parameters to be converted. 975 | :type params: List or numpy array 976 | :param param_is_log: Optional. A list indicating whether each parameter should be converted to log scale. If not provided, it will be determined based on the model properties. 977 | :type param_is_log: List or numpy array, default None 978 | :param eic: Optional. A flag indicating whether the model properties are based on EIC. Defaults to False. If True, the model properties will be used to determine param_is_log. If False, param_is_log will be used as is. 979 | :type eic: bool, default False 980 | :return: The parameters converted to logarithmic scale. 981 | :rtype: List or numpy array 982 | """ 983 | if param_is_log is None: 984 | param_is_log = modelProperties(eic).PARAM_IS_LOG 985 | 986 | ret = params.copy() 987 | for i in range(len(params)): 988 | if param_is_log[i]: 989 | ret[i] = np.log10(params[i]) 990 | return ret 991 | --------------------------------------------------------------------------------