diff --git a/code_new/RD_Dynesty_Fits/.ipynb_checkpoints/LICENSE-checkpoint.txt b/code_new/RD_Dynesty_Fits/.ipynb_checkpoints/LICENSE-checkpoint.txt new file mode 100644 index 0000000000000000000000000000000000000000..eb444799ca80d4bc82bf638c0f6085bce2106c56 --- /dev/null +++ b/code_new/RD_Dynesty_Fits/.ipynb_checkpoints/LICENSE-checkpoint.txt @@ -0,0 +1,15 @@ + Copyright (C) 2021 Xisco Jimenez Forteza + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 3 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. \ No newline at end of file diff --git a/code_new/RD_Dynesty_Fits/.ipynb_checkpoints/README-checkpoint.md b/code_new/RD_Dynesty_Fits/.ipynb_checkpoints/README-checkpoint.md new file mode 100644 index 0000000000000000000000000000000000000000..7cc7b24cd05b42cde9b1308fa2bbd6de4f09c4dc --- /dev/null +++ b/code_new/RD_Dynesty_Fits/.ipynb_checkpoints/README-checkpoint.md @@ -0,0 +1,2 @@ +A package that fits RD waveforms with the dynesty sampler + diff --git a/code_new/RD_Dynesty_Fits/.ipynb_checkpoints/Run_Setup-checkpoint.ipynb b/code_new/RD_Dynesty_Fits/.ipynb_checkpoints/Run_Setup-checkpoint.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..1d8a77990e8b9c78cf92d0eb4f3ec626d285eb66 --- /dev/null +++ b/code_new/RD_Dynesty_Fits/.ipynb_checkpoints/Run_Setup-checkpoint.ipynb @@ -0,0 +1,167 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 4, + "id": "square-toddler", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "b''" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "\"\"\"\n", + "Created by Sumit Kumar on 2020-03-08 && modified by Xisco on 2021-04\n", + "Last modified:\n", + "\"\"\"\n", + "\n", + "import os, sys, numpy, glob, argparse\n", + "from datetime import date\n", + "import subprocess\n", + "from subprocess import call\n", + "import re\n", + "from configparser import ConfigParser\n", + "\n", + "today = date.today()\n", + "date = today.strftime(\"%Y%m%d\")\n", + "\n", + "runname='run_0_mock'\n", + "nmax = 0\n", + "config_file ='config_n0_to_1_mock.ini'\n", + "overwrite = True\n", + "\n", + "######\n", + "times = '(0 0.2 0.4 0.8 1.2 2 2.5 5 7.5 10 12 15 18 20)'\n", + "accounting_group = 'cbc.test.pe_ringdown'\n", + "cpus=8\n", + "nlive_points = 2000\n", + "req_memory=\"16GB\"\n", + "not_user='frjifo@aei.mpg.de'\n", + "pythonfile='/work/francisco.jimenez/sio/git/rdstackingproject/code_new/RD_Fits.py'\n", + "pythonscript='/work/francisco.jimenez/venv/bin/python'\n", + "#######################################################\n", + "\n", + "pwd = os.getcwd()\n", + "run_dir = '%s/%s'%(pwd,runname)\n", + "logs_dir = '%s/logs'%run_dir\n", + "\n", + "os.system('mkdir -p %s'%logs_dir)\n", + "os.system('cp %s %s/'%(config_file,run_dir))\n", + "\n", + "###########################################################################\n", + "# Creating Condor submit file\n", + "###########################################################################\n", + "filename1 = '%s/%s'%(run_dir,'condor_submit')\n", + "text_file1 = open(filename1 + \".sub\", \"w\")\n", + "text_file1.write(\"universe = vanilla\\n\")\n", + "text_file1.write(\"getenv = true\\n\")\n", + "text_file1.write(\"# run script -- make sure that condor has execute permission for this file (chmod a+x script.py)\\n\")\n", + "text_file1.write(\"executable = \"'%s/%s'%(run_dir,runname+'.sh \\n'))\n", + "text_file1.write(\"# file to dump stdout (this directory should exist)\\n\")\n", + "text_file1.write(\"output = %s/%s-$(Process).out\\n\"%(logs_dir,runname))\n", + "text_file1.write(\"# file to dump stderr\\n\")\n", + "text_file1.write(\"error = %s/%s-$(Process).err\\n\"%(logs_dir,runname))\n", + "text_file1.write(\"# condor logs\\n\")\n", + "text_file1.write(\"log = %s/%s-$(Process).log\\n\"%(logs_dir,runname))\n", + "text_file1.write(\"initialdir = %s \\n\"%run_dir)\n", + "text_file1.write(\"notify_user =\"+not_user+' \\n')\n", + "text_file1.write(\"notification = Complete\\n\")\n", + "text_file1.write('''arguments = \"-processid $(Process)\" \\n''')\n", + "text_file1.write(\"request_memory = \"+str(req_memory)+\"\\n\")\n", + "text_file1.write(\"request_cpus = \"+str(cpus)+\"\\n\") \n", + "text_file1.write(\"on_exit_remove = (ExitBySignal == False) || ((ExitBySignal == True) && (ExitSignal != 11))\\n\")\n", + "text_file1.write(\"accounting_group = %s\\n\"%accounting_group)\n", + "text_file1.write(\"queue 1\\n\")\n", + "text_file1.write(\"\\n\")\n", + "text_file1.close()\n", + "\n", + "###########################################################\n", + "# Creating python executable file\n", + "############################################################\n", + "filename2 = run_dir+'/'+runname+'.sh'\n", + "text_file2 = open(filename2, \"w\") \n", + "text_file2.write(\"#! /bin/bash \\n\")\n", + "text_file2.write(\"\\n\")\n", + "text_file2.write(\"times=\"+times+\"\\n\")\n", + "text_file2.write(\"config_file=\"+config_file+\"\\n\")\n", + "text_file2.write(\"pythonfile=\"+pythonfile+\"\\n\")\n", + "text_file2.write(\"pythonscript=\"+pythonscript+\"\\n\")\n", + "text_file2.write(\"\\n\")\n", + "text_file2.write(\"for i in ${times[@]}; do\\n\")\n", + "text_file2.write(\" awk -v a=\\\"$i\\\" '/^tshift/ && $3 != \\\"supplied\\\" { $3=a } { print }' $config_file > tmp && mv tmp $config_file\\n\")\n", + "text_file2.write(\" $pythonscript $pythonfile -c $config_file \\n\")\n", + "text_file2.write(\"done\\n\")\n", + "text_file2.write(\"awk -v a=\\\"0\\\" '/^tshift/ && $3 != \\\"supplied\\\" { $3=a } { print }' $config_file > tmp && mv tmp $config_file \\n\")\n", + "text_file2.write(\"\\n\")\n", + "text_file2.close()\n", + "os.system('chmod u+x %s'%filename2)\n", + "\n", + "os.system('cp '+runname+'.sh %s/'%run_dir)\n", + "os.system('chmod u+x ./'+runname+'.sh')\n", + "os.system('cd '+run_dir)\n", + "\n", + "###########################################################\n", + "# Checking the configuration file and adding some important replacements\n", + "############################################################\n", + "\n", + "filename3 = '%s/%s'%(run_dir,config_file)\n", + "# change the number of cores\n", + "bashCommand = \"awk -v a=\"+str(cpus)+\" '/^nb_cores/ && $3 != \\\"supplied\\\" { $3=a } { print }' \"+str(config_file)+\" > tmp && mv tmp \"+str(config_file);\n", + "subprocess.call(bashCommand,shell=True)\n", + "\n", + "filename3 = '%s/%s'%(run_dir,config_file)\n", + "# change the number of nmax\n", + "bashCommand = \"awk -v a=\"+str(nmax)+\" '/^nmax/ && $3 != \\\"supplied\\\" { $3=a } { print }' \"+str(config_file)+\" > tmp && mv tmp \"+str(config_file);\n", + "subprocess.call(bashCommand,shell=True)\n", + "\n", + "filename3 = '%s/%s'%(run_dir,config_file)\n", + "# change the number of nmax\n", + "bashCommand = \"awk -v a=\"+str(nlive_points)+\" '/^npoints/ && $3 != \\\"supplied\\\" { $3=a } { print }' \"+str(config_file)+\" > tmp && mv tmp \"+str(config_file);\n", + "subprocess.call(bashCommand,shell=True)\n", + "\n", + "# change the overwrite parameter\n", + "bashCommand = \"awk -v a=\"+str(overwrite)+\" '/^overwrite/ && $3 != \\\"supplied\\\" { $3=a } { print }' \"+str(config_file)+\" > tmp && mv tmp \"+str(config_file);\n", + "subprocess.call(bashCommand,shell=True)\n", + " \n", + "\n", + "###########################################################\n", + "# Submit the job\n", + "############################################################\n", + "filename4 = '%s/%s'%(run_dir,'condor_submit.sub')\n", + "bashCommand = ['condor_submit', str(filename4)]\n", + "process = subprocess.Popen(bashCommand, stdout=subprocess.PIPE,stderr=subprocess.PIPE);\n", + "output,error = process.communicate()\n", + "error" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.7" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/code_new/RD_Dynesty_Fits/.ipynb_checkpoints/pyproject-checkpoint.toml b/code_new/RD_Dynesty_Fits/.ipynb_checkpoints/pyproject-checkpoint.toml new file mode 100644 index 0000000000000000000000000000000000000000..3510d21927d37b6c7be21a9d87123c4885a7a8c7 --- /dev/null +++ b/code_new/RD_Dynesty_Fits/.ipynb_checkpoints/pyproject-checkpoint.toml @@ -0,0 +1,16 @@ +[build-system] +requires = [ + "setuptools>=42", + "wheel", + "corner", + "dynesty", + "json", + "h5py", + "qnm", + "pickle", + "pandas", + "csv", + "romspline", + "pytest", +] +build-backend = "setuptools.build_meta" diff --git a/code_new/RD_Dynesty_Fits/.ipynb_checkpoints/setup-checkpoint.cfg b/code_new/RD_Dynesty_Fits/.ipynb_checkpoints/setup-checkpoint.cfg new file mode 100644 index 0000000000000000000000000000000000000000..fd7d91305b31e029ca76c33f5287300018353e98 --- /dev/null +++ b/code_new/RD_Dynesty_Fits/.ipynb_checkpoints/setup-checkpoint.cfg @@ -0,0 +1,26 @@ +[metadata] +# replace with your username: +name = frcojimenez +version = 0.1 +author = Xisco Jimenez Forteza +author_email = francisco.jimenez.forteza@mpg.aei.de +description = A package that fits RD waveforms with the dynesty sampler +long_description = file: README.md +long_description_content_type = text/markdown +url = http://pypi.python.org/pypi/RD_Dynesty_Fits/ +project_urls = + Bug Tracker = https://github.com/frcojimenez/RD_Dynest_Fits/issues +classifiers = + Programming Language :: Python :: 3 + License :: OSI Approved :: MIT License + Operating System :: OS Independent + +[options] +package_dir = + = src +packages = find: +python_requires = >=3.6 + +[options.packages.find] +where = src +#There are a variety of metadata and option \ No newline at end of file diff --git a/code_new/RD_Dynesty_Fits/.ipynb_checkpoints/setup-checkpoint.py b/code_new/RD_Dynesty_Fits/.ipynb_checkpoints/setup-checkpoint.py new file mode 100644 index 0000000000000000000000000000000000000000..deb9e2b5a3f7b3fd493ec077b8e8bd62323a70c1 --- /dev/null +++ b/code_new/RD_Dynesty_Fits/.ipynb_checkpoints/setup-checkpoint.py @@ -0,0 +1,25 @@ +from setuptools import setup + +setup( + name='RD_Dynesty_Fits', + version='0.1.0', + author='Xisco Jimenez Forteza', + author_email='francisco.jimenez.forteza@mpg.aei.de', + packages=['RD_Dynesty_Fits', 'RD_Dynesty_Fits.test'], + package_dir={'':'/work/francisco.jimenez/sio/git/rdstackingproject/code_new/RD_Dynesty_Fits'}, + scripts=['src/RD_Dynesty_Fits.py','src/rdown_pe.py','src/rdown_utilities.py','src/rdown.py','src/read_data.py'], + url='http://pypi.python.org/pypi/RD_Dynesty_Fits/', + license='LICENSE.txt', + description='A package that fits RD waveforms with the dynesty sampler', + long_description=open('README.md').read(), + install_requires=["setuptools>=42", + "wheel", + "corner", + "dynesty", + "h5py", + "qnm", + "pandas", + "romspline", + "pytest", + ], +) diff --git a/code_new/RD_Dynesty_Fits/LICENSE.txt b/code_new/RD_Dynesty_Fits/LICENSE.txt new file mode 100644 index 0000000000000000000000000000000000000000..eb444799ca80d4bc82bf638c0f6085bce2106c56 --- /dev/null +++ b/code_new/RD_Dynesty_Fits/LICENSE.txt @@ -0,0 +1,15 @@ + Copyright (C) 2021 Xisco Jimenez Forteza + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 3 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. \ No newline at end of file diff --git a/code_new/RD_Dynesty_Fits/RD_Dynesty_Fits.egg-info/PKG-INFO b/code_new/RD_Dynesty_Fits/RD_Dynesty_Fits.egg-info/PKG-INFO new file mode 100644 index 0000000000000000000000000000000000000000..99d3a4a2d2c8cbf363c6056bd52828e693490b85 --- /dev/null +++ b/code_new/RD_Dynesty_Fits/RD_Dynesty_Fits.egg-info/PKG-INFO @@ -0,0 +1,18 @@ +Metadata-Version: 2.1 +Name: RD-Dynesty-Fits +Version: 0.1.0 +Summary: A package that fits RD waveforms with the dynesty sampler +Home-page: http://pypi.python.org/pypi/RD_Dynesty_Fits/ +Author: Xisco Jimenez Forteza +Author-email: francisco.jimenez.forteza@mpg.aei.de +License: LICENSE.txt +Project-URL: Bug Tracker, https://github.com/frcojimenez/RD_Dynest_Fits/issues +Description: A package that fits RD waveforms with the dynesty sampler + + +Platform: UNKNOWN +Classifier: Programming Language :: Python :: 3 +Classifier: License :: OSI Approved :: MIT License +Classifier: Operating System :: OS Independent +Requires-Python: >=3.6 +Description-Content-Type: text/markdown diff --git a/code_new/RD_Dynesty_Fits/RD_Dynesty_Fits.egg-info/SOURCES.txt b/code_new/RD_Dynesty_Fits/RD_Dynesty_Fits.egg-info/SOURCES.txt new file mode 100644 index 0000000000000000000000000000000000000000..8b427adacfe40a6a31c0cc3f9642f556cb45c51f --- /dev/null +++ b/code_new/RD_Dynesty_Fits/RD_Dynesty_Fits.egg-info/SOURCES.txt @@ -0,0 +1,23 @@ +LICENSE.txt +README.md +pyproject.toml +setup.cfg +setup.py +/work/francisco.jimenez/sio/git/rdstackingproject/code_new/RD_Dynesty_Fits/RD_Dynesty_Fits/RD_Dynesty_Fits.py +/work/francisco.jimenez/sio/git/rdstackingproject/code_new/RD_Dynesty_Fits/RD_Dynesty_Fits/RD_Fits.py +/work/francisco.jimenez/sio/git/rdstackingproject/code_new/RD_Dynesty_Fits/RD_Dynesty_Fits/__init__.py +/work/francisco.jimenez/sio/git/rdstackingproject/code_new/RD_Dynesty_Fits/RD_Dynesty_Fits/rdown.py +/work/francisco.jimenez/sio/git/rdstackingproject/code_new/RD_Dynesty_Fits/RD_Dynesty_Fits/rdown_pe.py +/work/francisco.jimenez/sio/git/rdstackingproject/code_new/RD_Dynesty_Fits/RD_Dynesty_Fits/rdown_utilities.py +/work/francisco.jimenez/sio/git/rdstackingproject/code_new/RD_Dynesty_Fits/RD_Dynesty_Fits/read_data.py +/work/francisco.jimenez/sio/git/rdstackingproject/code_new/RD_Dynesty_Fits/RD_Dynesty_Fits.egg-info/PKG-INFO +/work/francisco.jimenez/sio/git/rdstackingproject/code_new/RD_Dynesty_Fits/RD_Dynesty_Fits.egg-info/SOURCES.txt +/work/francisco.jimenez/sio/git/rdstackingproject/code_new/RD_Dynesty_Fits/RD_Dynesty_Fits.egg-info/dependency_links.txt +/work/francisco.jimenez/sio/git/rdstackingproject/code_new/RD_Dynesty_Fits/RD_Dynesty_Fits.egg-info/requires.txt +/work/francisco.jimenez/sio/git/rdstackingproject/code_new/RD_Dynesty_Fits/RD_Dynesty_Fits.egg-info/top_level.txt +/work/francisco.jimenez/sio/git/rdstackingproject/code_new/RD_Dynesty_Fits/RD_Dynesty_Fits/test/__init__.py +src/RD_Dynesty_Fits.py +src/rdown.py +src/rdown_pe.py +src/rdown_utilities.py +src/read_data.py \ No newline at end of file diff --git a/code_new/RD_Dynesty_Fits/RD_Dynesty_Fits.egg-info/dependency_links.txt b/code_new/RD_Dynesty_Fits/RD_Dynesty_Fits.egg-info/dependency_links.txt new file mode 100644 index 0000000000000000000000000000000000000000..8b137891791fe96927ad78e64b0aad7bded08bdc --- /dev/null +++ b/code_new/RD_Dynesty_Fits/RD_Dynesty_Fits.egg-info/dependency_links.txt @@ -0,0 +1 @@ + diff --git a/code_new/RD_Dynesty_Fits/RD_Dynesty_Fits.egg-info/requires.txt b/code_new/RD_Dynesty_Fits/RD_Dynesty_Fits.egg-info/requires.txt new file mode 100644 index 0000000000000000000000000000000000000000..c8a98c44436fc8e96121781ec38c78021b032938 --- /dev/null +++ b/code_new/RD_Dynesty_Fits/RD_Dynesty_Fits.egg-info/requires.txt @@ -0,0 +1,9 @@ +setuptools>=42 +wheel +corner +dynesty +h5py +qnm +pandas +romspline +pytest diff --git a/code_new/RD_Dynesty_Fits/RD_Dynesty_Fits.egg-info/top_level.txt b/code_new/RD_Dynesty_Fits/RD_Dynesty_Fits.egg-info/top_level.txt new file mode 100644 index 0000000000000000000000000000000000000000..3dd4cf60b3a76529c5ee75522f01ab4b62418492 --- /dev/null +++ b/code_new/RD_Dynesty_Fits/RD_Dynesty_Fits.egg-info/top_level.txt @@ -0,0 +1 @@ +RD_Dynesty_Fits diff --git a/code_new/RD_Dynesty_Fits/RD_Dynesty_Fits/.ipynb_checkpoints/rdown-checkpoint.py b/code_new/RD_Dynesty_Fits/RD_Dynesty_Fits/.ipynb_checkpoints/rdown-checkpoint.py new file mode 100644 index 0000000000000000000000000000000000000000..1357ccbf98a454670c79fb49574d7fe1447e243a --- /dev/null +++ b/code_new/RD_Dynesty_Fits/RD_Dynesty_Fits/.ipynb_checkpoints/rdown-checkpoint.py @@ -0,0 +1,208 @@ +# Copyright (C) 2021 Xisco Jimenez Forteza +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + +# +# ============================================================================= +# +# Preamble +# +# ============================================================================= +# +# Module to generate RD waveforms. + +import numpy as np +import qnm +import os + +f_fpars= [[2.95845, -2.58697, 0.0533469], [2.12539, -1.78054, 0.0865503], [1.74755, -1.44776, 0.123666], [1.78287, -1.53203, 0.129475], [2.04028, -1.83224, 0.112497]] +q_fpars=[[0.584077, 1.52053, -0.480658], [0.00561441, 0.630715, -0.432664], [-0.197965, 0.515956, -0.369706], [-0.275097, 0.455691, -0.331543], [-0.287596, 0.398514, -0.309799]] + + +c=2.99792458*10**8;G=6.67259*10**(-11);MS=1.9885*10**30; +class Ringdown_Spectrum: + """RDown model generator""" + def __init__(self,mf,af,l,m,n=4,s=-2,time=[],fixed=False,qnm_model='berti'): + self.mf = mf + self.af = af + self.l = l + self.m = m + self.n = n + self.time = time + self.grav_220 = [qnm.modes_cache(s=s,l=self.l,m=self.m,n=i) for i in range (0,self.n+1)] + self.dim = self.n+1 + self.fixed = fixed + self.qnm_model = qnm_model + dict_omega = {'berti': self.QNM_Berti , 'qnm': self.QNM_spectrum} + dic = {'w-tau':self.rd_model_wtau , 'w-q': self.rd_model_wq, 'w-tau-fixed':self.rd_model_wtau_fixed,'w-tau-fixed-m-af': self.rd_model_wtau_m_af} + + if len(self.time)==0: + self.time = np.arange(0,100,0.1) + + if self.fixed: + omegas_new=np.asarray([self.grav_220[i](a=self.af)[0] for i in range (0,self.dim)]) + self.w = (np.real(omegas_new))/self.mf + self.tau=-1/(np.imag(omegas_new))*self.mf + + + def QNM_spectrum(self): + """ It computes the RD frequencies and damping times in NR units. + """ + omegas_new=np.asarray([self.grav_220[i](a=self.af)[0] for i in range (0,self.n+1)]) + w_m_a = (np.real(omegas_new))/self.mf + tau_m_a=-1/(np.imag(omegas_new))*self.mf + + return (w_m_a, tau_m_a) + + def QNM_Berti(self,rdowndata): + """ It computes the RD frequencies and damping times in NR units. + """ + position=np.argmax(rdowndata[0,0] >= (self.af)) + #w_m_a=f1+f2*(1-af)**f3 + w_m_a=[None]*(self.n+1) + tau_ma_a=[None]*(self.n+1) + + for i in range(self.n+1): + qnm=rdowndata[i,1:3,position] + w_m_a[i] = qnm[0]/self.mf + tau_ma_a[i] = -1/(qnm[1])*self.mf + + return w_m_a, tau_ma_a + + + def w_fpars_Berti(self,n): + return f_fpars[n] + + def tau_qpars_Berti(self,n): + return q_fpars[n] + + def mass_from_wtau(self,n,w,tau): + f1,f2,f3 = w_fpars_Berti(n) + q1,q2,q3 = tau_qpars_Berti(n) + res=(f1 + f2*(2**(-1/q3)*((-2*q1 + w*tau)/q2)**(1/q3))**f3)/w + return res + + def spin_from_wtau(self,n,w,tau): + f1,f2,f3 = w_fpars_Berti(n) + q1,q2,q3 = tau_qpars_Berti(n) + res=1 - 2**(-1/q3)*((-2*q1 + w*tau)/q2)**(1/q3) + return res + + def mass_from_wtau_loop(self,w,tau,l,m): + res=[None]*dim + for n in range (0,dim): + f1,f2,f3 = w_fpars_Berti(n) + q1,q2,q3 = tau_qpars_Berti(n) + res[n]=(f1 + f2*(2**(-1/q3)*((-2*q1 + w[n]*tau[n])/q2)**(1/q3))**f3)/w[n] + return res + + def spin_from_wtau_loop(self,w,tau,l,m): + res=[None]*dim + for n in range (0,dim): + f1,f2,f3 = w_fpars_Berti(n) + q1,q2,q3 = tau_qpars_Berti(n) + res[n]= 1 - 2**(-1/q3)*((-2*q1 + w[n]*tau[n])/q2)**(1/q3) + return res + + + def rd_model_wtau(self,theta): + """RD model parametrized with the damping time tau. + """ + assert int(len(theta)/4) == self.dim, 'Please recheck your n and parameters' + + wvars = theta[ : (self.dim)] + tvars = theta[(self.dim) : 2*(self.dim)] + xvars = theta[2*(self.dim) : 3*(self.dim)] + yvars = theta[3*(self.dim) : ] + + ansatz = 0 + for i in range (0,self.dim): + ansatz += (xvars[i]*np.exp(1j*yvars[i]))*np.exp(-self.time/tvars[i]) * (np.cos(wvars[i]*self.time)-1j*np.sin(wvars[i]*self.time)) + # -1j to agree with SXS convention + return ansatz + + def rd_model_wtau_m_af(theta): + """RD model parametrized with the damping time tau and with the QNM spectrum fixd to GR. The QNM spectrum is given from the mass and spin. + """ + xvars = theta[ : (dim)] + yvars = theta[(dim) : 2*(dim)] + mass_vars = theta[index_mass] + spin_vars = theta[index_spin] + + w_m_a , tau_m_a = dict_omega[self.qnm_model](mass_vars,spin_vars,2,2) + + ansatz = 0 + for i in range (0,dim): + ansatz += (xvars[i]*np.exp(1j*yvars[i]))*np.exp(-timesrd_final_tsh/tau_m_a[i]) * (np.cos(w_m_a[i]*timesrd_final_tsh)-1j*np.sin(w_m_a[i]*timesrd_final_tsh)) + # -1j to agree with SXS convention + return ansatz + + def rd_model_wtau_fixed(theta): + """RD model parametrized with the damping time tau and with the QNM spectrum fixd to GR. + """ + xvars = theta[ : (dim)] + yvars = theta[(dim) : 2*(dim)] + + ansatz = 0 + for i in range (0,dim): + ansatz += (xvars[i]*np.exp(1j*yvars[i]))*np.exp(-timesrd_final_tsh/tau[i]) * (np.cos(w[i]*timesrd_final_tsh)-1j*np.sin(w[i]*timesrd_final_tsh)) + # -1j to agree with SXS convention + return ansatz + + def rd_model_wq(self,theta): + """RD model parametrized with the quality factor q. + """ + assert int(len(theta)/4) == self.dim, 'Please recheck your n and parameters' + + wvars = theta[ : (self.dim)] + qvars = theta[(self.dim) : 2*(self.dim)] + xvars = theta[2*(self.dim) : 3*(self.dim)] + yvars = theta[3*(self.dim) : ] + + ansatz = 0 + for i in range (0,self.dim): + ansatz += (xvars[i]*np.exp(1j*yvars[i]))*np.exp(-self.time*np.pi*wvars[i]/qvars[i])*(np.cos(wvars[i]*self.time)-1j*np.sin(wvars[i]*self.time)) + # -1j to agree with SXS convention + return ansatz + + def rd_model_wq_fixed(self,theta): + """RD model parametrized with the damping time tau and with the QNM spectrum fixd to GR. + """ + xvars = theta[ : (self.dim)] + yvars = theta[(self.dim) : 2*(self.dim)] + + ansatz = 0 + for i in range (0,self.dim): + ansatz += (xvars[i]*np.exp(1j*yvars[i]))*np.exp(-self.time/self.tau[i]) * (np.cos(self.w[i]*self.time)-1j*np.sin(self.w[i]*self.time)) + # -1j to agree with SXS convention + return ansatz + + + def rd_model_wq_m_a(self,theta): + """RD model parametrized with the damping time tau and with the QNM spectrum fixd to GR. The QNM spectrum is given from the mass and spin. + """ + xvars = theta[ : (self.dim)] + yvars = theta[(self.dim) : 2*(self.dim)] + mass_vars = theta[-2] + spin_vars = theta[-1] + + w_m_a , tau_m_a = QNM_spectrum() + + ansatz = 0 + for i in range (0,dim): + ansatz += (xvars[i]*np.exp(1j*yvars[i]))*np.exp(-timesrd_final_tsh/tau_m_a[i]) * (np.cos(w_m_a[i]*timesrd_final_tsh)-1j*np.sin(w_m_a[i]*timesrd_final_tsh)) + # -1j to agree with SXS convention + return ansatz \ No newline at end of file diff --git a/code_new/RD_Dynesty_Fits/RD_Dynesty_Fits/.ipynb_checkpoints/rdown_utilities-checkpoint.py b/code_new/RD_Dynesty_Fits/RD_Dynesty_Fits/.ipynb_checkpoints/rdown_utilities-checkpoint.py new file mode 100644 index 0000000000000000000000000000000000000000..c4a5b95c1c26beb418d2457fbd2a2b09212778c3 --- /dev/null +++ b/code_new/RD_Dynesty_Fits/RD_Dynesty_Fits/.ipynb_checkpoints/rdown_utilities-checkpoint.py @@ -0,0 +1,318 @@ +# Copyright (C) 2021 Xisco Jimenez Forteza +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + +# +# ============================================================================= +# +# Preamble +# +# ============================================================================= +# +# Module to run PE on RD data +import numpy as np +from dynesty.utils import resample_equal +from dynesty import utils as dyfunc +import os +import csv +import pandas as pd +import pickle + +def posterior_samples(sampler): + """ + Returns posterior samples from nested samples and weights + given by dynsety sampler + """ + + dynesty_samples = sampler.results['samples'] + wt = np.exp(sampler.results['logwt'] - + sampler.results['logz'][-1]) + # Make sure that sum of weights equal to 1 + weights = wt/np.sum(wt) + posterior_dynesty = dyfunc.resample_equal(dynesty_samples, weights) + return posterior_dynesty + +def FFT_FreqBins(times): + Len = len(times) + DeltaT = times[-1]- times[0] + dt = DeltaT/(Len-1) + dnu = 1/(Len*dt) + maxfreq = 1/(2*dt) + add = dnu/4 + + p = np.arange(0.0,maxfreq+add,dnu) + m = np.arange(p[-1]-(2*maxfreq)+dnu,-dnu/2+add,dnu) + res=np.concatenate((p,m)) + + return res + +def hFromPsi4FFI(tpsi4,f0): + + timecheck1=tpsi4[-2,0]-tpsi4[-1,0] + timecheck2=tpsi4[1,0]-tpsi4[0,0] + + if np.abs(timecheck1-timecheck2)>=0.0001: + print("The data might not be equally sampled!!") + + times,data= tpsi4[:,0],tpsi4[:,1] + + freqs = FT_FreqBins(xaxis.real).real + position = np.argmax(freqs >= f0) + freqs[:position]=f0*np.ones(len(freqs[:position])) + freqs=2*np.pi*freqs + + fdata=fft(data) + len(myTable)*ifft(- fdata/floor**2); + np.stack((times,data)).T + + +def twopoint_autocovariance(t,n): + """ It computes the two-point autocovariance function. + """ + dt=t[1]-t[0] + res = np.zeros(len(n)) + taus = np.zeros(len(n)) + for tau in range(0,int(len(n)/2)): + ntau=np.roll(n, tau) + taus[tau] = t[tau] + res[tau]=np.sum(n*ntau).real + return (taus[:int(len(n)/2)],res[:int(len(n)/2)]) + +def save_object(obj, filename): + with open(filename, 'wb') as output: # Overwrites any existing file. + pickle.dump(obj, output, pickle.HIGHEST_PROTOCOL) + + +def EasyMatchT(t,h1,h2,tmin,tmax): + """ It computes the time-domain match for (h1|h2) complex waveforms. + """ + pos = np.argmax(t >= (tmin)); + + h1red=h1[pos:]; + h2red=h2[pos:]; + + norm1=np.sum(np.abs(h1red)**2) + norm2=np.sum(np.abs(h2red)**2) + + myTable=h1red*np.conjugate(h2red) + res=((np.sum(myTable)/np.sqrt(norm1*norm2))).real + + return res + +def EasySNRT(t,h1,h2,tmin,tmax): + """ It computes the time-domain snr for (h1|h2) complex waveforms. + """ + pos = np.argmax(t >= (tmin)); + + h1red=h1[pos:]; + h2red=h2[pos:]; + + myTable=h1red*np.conjugate(h2red) + res=2*np.sqrt((np.sum(myTable)).real) + + return res + +def FindTmaximum(y): + """ It determines the maximum absolute value of the complex waveform. + """ + absval = np.sqrt(y[:,1]*y[:,1]+y[:,2]*y[:,2]) + vmax=np.max(absval) + index = np.argmax(absval == vmax) + timemax=y[index,0] + + return timemax + +def export_logz_files(output_file,pars): + sim_num, nmax, tshift, evidence, evidence_error = pars + + """ + Generate the logz.csv files you want to export the data to. + file_type must be one of this options: [corner_plot,corner_plot_extra,diagnosis,fit,post_samples,sampler_results,log_z] + """ + + summary_titles=['n','id','t_shift','dlogz','dlogz_err'] + if os.path.exists(output_file): + outvalues = np.array([[nmax, sim_num, tshift, evidence,evidence_error]]) + else: + outvalues = np.array([summary_titles,[nmax, sim_num, tshift, evidence,evidence_error]]) + + with open(output_file, 'a') as file: + writer = csv.writer(file) + if (outvalues.shape)[0]>1 : + writer.writerows(outvalues) + else: + writer.writerow(outvalues[0]) + + return + +def export_bestvals_files(best_data_file,postsamps,pars): + + tshift, lenpriors, labels = pars + + sigma_vars_m = np.empty(lenpriors) + sigma_vars_p = np.empty(lenpriors) + sigma_vars = np.empty(lenpriors) + sigma_vars_ml = np.empty(lenpriors) + for i in range(lenpriors): + amps_aux = postsamps[:,i] + sigma_vars_m[i] = np.quantile(amps_aux, 0.05) + sigma_vars[i] = np.quantile(amps_aux, 0.5) + sigma_vars_ml[i] = postsamps[-1,i] + sigma_vars_p[i] = np.quantile(amps_aux, 0.95) + + sigma_vars_all = [sigma_vars,sigma_vars_ml,sigma_vars_m,sigma_vars_p] + sigma_vars_all=np.stack([sigma_vars,sigma_vars_ml,sigma_vars_m,sigma_vars_p], axis=0) + + key =['max val','max val ml','lower bound','higher bound'] + dfslist = [pd.DataFrame(np.concatenate(([tshift],sigma_vars_all[i])).reshape((-1,lenpriors+1)), columns=np.concatenate((['tshift'],labels)), index = [key[i]]) for i in range(4)] + df2 = pd.concat(dfslist) + if os.path.exists(best_data_file): + df2.to_csv(best_data_file, mode='a', header=False,index = True) + else: + df2.to_csv(best_data_file, index = True) + + + +def define_labels(dim,model,fitnoise): + wstr = r'$\omega_' + + if model == 'w-tau': + taustr = r'$\tau_' + elif model == 'w-q': + taustr = r'$q_' + elif model == 'w-tau-fixed': + taustr = r'$dumb_var}' + elif model == 'w-tau-fixed-m-af': + taustr = r'$\tau_' + + ampstr = r'$A_' + phasestr = r'$\phi_' + + w_lab = [None] * dim + tau_lab = [None] * dim + amp_lab = [None] * dim + pha_lab = [None] * dim + mass_lab = ['mass'] + spin_lab = ['spin'] + + for i in range(dim): + w_lab[i] = wstr+str(i)+'$' + tau_lab[i] = taustr+str(i)+'$' + amp_lab[i] = ampstr+str(i)+'$' + pha_lab[i] = phasestr+str(i)+'$' + + + labels = np.concatenate((w_lab,tau_lab,amp_lab,pha_lab)) + + if model=='w-tau-fixed': + labels = np.concatenate((amp_lab,pha_lab)) + + if model=='w-tau-fixed-m-af': + pha_lab[i] = phasestr+str(i)+'$' + + labels = np.concatenate((amp_lab,pha_lab,mass_lab,spin_lab)) + + if fitnoise: + noise_lab = ['noise'] + labels = np.concatenate((labels,noise_lab)) + + return labels + +def get_truths(model,pars,fitnoise): + w, tau, mf, af , npamps = pars + if model == 'w-q': + tau_val = np.pi*w*tau + truths = np.concatenate((w,tau_val,npamps)) + elif model == 'w-tau': + tau_val = tau + truths = np.concatenate((w,tau_val,npamps)) + elif model == 'w-tau-fixed': + truths = npamps + elif model == 'w-tau-fixed-m-af': + truths = np.concatenate((npamps,[mf],[af])) + + if fitnoise: + truths = np.concatenate((truths,[1])) + + return truths + +def get_best_amps(pars,parser=None,nr_code=None): + nmax,model,samps_tr,half_points = pars + + + if model=='w-tau-fixed': + rg = (nmax+1) + elif model=='w-tau-fixed': + rg = (nmax+1)+2 + else: + rg = (nmax+1)*2 + + + if model=='w-tau-fixed-a-mf': + npamps = np.empty((nmax+1)) + for i in range(0,(nmax+1)): + amps_aux = samps_tr[i+rg][half_points:-1] + npamps[i] = np.quantile(amps_aux, 0.5) + else : + npamps = np.empty((nmax+1)*2) + for i in range(0,(nmax+1)*2): + amps_aux = samps_tr[i][half_points:-1] + npamps[i] = np.quantile(amps_aux, 0.5) + + if nr_code == 'Mock-data': + nm_mock = parser.get('rd-mock-parameters','nm_mock') + nm_mock = np.int(nm_mock) + amp_mock=np.empty(nm_mock+1) + ph_mock=np.empty(nm_mock+1) + for i in range(nm_mock+1): + amp_mockp = parser.get('rd-mock-parameters','amp'+str(i)) + amp_mock[i] = np.float(amp_mockp) + ph_mockp=parser.get('rd-mock-parameters','phase'+str(i)) + ph_mock[i] = np.float(ph_mockp) + + npamps = np.concatenate((amp_mock,ph_mock)) + return npamps + +def convert_m_af_2_w_tau_post(res,fitnoise=False): + + samples_2=res.samples + samps=f2.results.samples + + if fitnoise: + fmass_spin=(samps.T)[-3:-1].T + else: + fmass_spin=(samps.T)[-2:].T + #fmass_spin=new_samples[-2:] + fmass_spin_dist=[None]*len(fmass_spin) + weight=np.exp(res.logwt - res.logz[-1]) + for i in range(len(fmass_spin)): + fmass_spin_dist[i]=np.concatenate(dict_omega[qnm_model](fmass_spin[i,0],fmass_spin[i,1],2,2)) + + fmass_spin_dist_v2=np.asarray(fmass_spin_dist) + new_samples = dyfunc.resample_equal(fmass_spin_dist_v2, weight) + + return new_samples + +def save_object(obj, filename): + with open(filename, 'wb') as output: # Overwrites any existing file. + pickle.dump(obj, output, pickle.HIGHEST_PROTOCOL) + +def rm_files(files): + """ rm all old files """ + for i in files: + if os.path.exists(i): + os.remove(i) + \ No newline at end of file diff --git a/code_new/RD_Dynesty_Fits/RD_Dynesty_Fits/.ipynb_checkpoints/read_data-checkpoint.py b/code_new/RD_Dynesty_Fits/RD_Dynesty_Fits/.ipynb_checkpoints/read_data-checkpoint.py new file mode 100644 index 0000000000000000000000000000000000000000..87185de6364a1b89cb9223329e31dc5bb3e58391 --- /dev/null +++ b/code_new/RD_Dynesty_Fits/RD_Dynesty_Fits/.ipynb_checkpoints/read_data-checkpoint.py @@ -0,0 +1,344 @@ +# Copyright (C) 2021 Xisco Jimenez Forteza +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + +# +# ============================================================================= +# +# Preamble +# +# ============================================================================= +# +# Module to run PE on RD data +import numpy as np +import rdown_utilities as rd_ut +import romspline +import rdown as rd +import h5py +import json +from scipy import interpolate +from scipy.interpolate import interp1d + + +def read_data(nr_code,sim_path,mf=1,af=0,parser=None,RD=True,tshift=0,tend = 100,metadata_file=None): + if nr_code=='SXS': + gw = {} + gw = h5py.File(sim_path, 'r') + gw_data = gw["Extrapolated_N3.dir"]["Y_l2_m2.dat"] + times = gw_data[:,0] + + metadata = {} + with open(metadata_file) as file: + metadata = json.load(file) + + af = metadata['remnant_dimensionless_spin'][-1] + mf = metadata['remnant_mass'] + + tmax=rd_ut.FindTmaximum(gw_data[round(len(gw_data)/2):]) + times = times - tmax + + if RD: + position = np.argmax(times >= 0) + gw_data = gw_data[:,1][position:]+1j*gw_data[:,2][position:] + times = times[times >= 0] + + elif nr_code=='Maya': + dt=0.1 + gw = {} + gw = h5py.File(sim_path, 'r') + gw_sxs_bbh_0305_amp = np.asarray(gw['amp_l2_m2/Y'])[6:] + times_1 = np.asarray(gw['amp_l2_m2/X'])[6:] + gw_sxs_bbh_0305_amp_int = romspline.ReducedOrderSpline(times_1, gw_sxs_bbh_0305_amp) + gw_sxs_bbh_0305_pha = np.asarray(gw['phase_l2_m2/Y'])[6:] + times = np.asarray(gw['phase_l2_m2/X'])[6:] + gw_sxs_bbh_0305_pha_int = romspline.ReducedOrderSpline(times, gw_sxs_bbh_0305_pha) + + tmin=max(times_1[0],times[0]) + tmax=min(times_1[-1],times[-1]) + times=np.arange(tmin,tmax,dt) + amps=gw_sxs_bbh_0305_amp_int(times) + phs=gw_sxs_bbh_0305_pha_int(times) + gw_sxs_bbh_0305 = np.asarray([times,amps*np.cos(phs),amps*np.sin(phs)]).T + gw5_sxs_bbh_0305 = gw_sxs_bbh_0305 + + times = gw_sxs_bbh_0305[:,0] + tmax=rd_ut.FindTmaximum(gw_sxs_bbh_0305[round(len(gw_sxs_bbh_0305)/2):]) + times = times - tmax + + #times 6--> x axis of your data + times5 = gw5_sxs_bbh_0305[:,0] + tmax5=rd_ut.FindTmaximum(gw5_sxs_bbh_0305[round(len(gw_sxs_bbh_0305)/2):]) + times5 = times5 - tmax5 + #Select the data from 0 onwards + position = np.argmax( times >= (t_align)) + position5 = np.argmax(times5 >= (t_align)) + gw_sxs_bbh_0305rd=gw_sxs_bbh_0305[position+1:] + gw_sxs_bbh_0305rd5=gw5_sxs_bbh_0305[position5+1:] + timesrd=gw_sxs_bbh_0305[position:-1][:,0][:] + timesrd5=gw5_sxs_bbh_0305[position5:-1][:,0][:] + + elif nr_code=='LaZeV': + dt=0.1 + gw = {} + gw = h5py.File(simulation_path_1, 'r') + gw_sxs_bbh_0305_amp = np.asarray(gw['amp_l2_m2/Y'])[6:] + times_1 = np.asarray(gw['amp_l2_m2/X'])[6:] + gw_sxs_bbh_0305_amp_int = romspline.ReducedOrderSpline(times_1, gw_sxs_bbh_0305_amp) + gw_sxs_bbh_0305_pha = np.asarray(gw['phase_l2_m2/Y'])[6:] + times = np.asarray(gw['phase_l2_m2/X'])[6:] + gw_sxs_bbh_0305_pha_int = romspline.ReducedOrderSpline(times, gw_sxs_bbh_0305_pha) + + tmin=max(times_1[0],times[0]) + tmax=min(times_1[-1],times[-1]) + times=np.arange(tmin,tmax,dt) + amps=gw_sxs_bbh_0305_amp_int(times) + phs=gw_sxs_bbh_0305_pha_int(times) + gw_sxs_bbh_0305 = np.asarray([times,amps*np.cos(phs),amps*np.sin(phs)]).T + gw5_sxs_bbh_0305 = gw_sxs_bbh_0305 + + times = gw_sxs_bbh_0305[:,0] + tmax=rd_ut.FindTmaximum(gw_sxs_bbh_0305[round(len(gw_sxs_bbh_0305)/2):]) + times = times - tmax + + #times 6--> x axis of your data + times5 = gw5_sxs_bbh_0305[:,0] + tmax5=rd_ut.FindTmaximum(gw5_sxs_bbh_0305[round(len(gw_sxs_bbh_0305)/2):]) + times5 = times5 - tmax5 + + #Select the data from 0 onwards + position = np.argmax( times >= (t_align)) + position5 = np.argmax(times5 >= (t_align)) + gw_sxs_bbh_0305rd=gw_sxs_bbh_0305[position+1:] + gw_sxs_bbh_0305rd5=gw5_sxs_bbh_0305[position5+1:] + timesrd=gw_sxs_bbh_0305[position:-1][:,0][:] + timesrd5=gw5_sxs_bbh_0305[position5:-1][:,0][:] + + elif nr_code=='Mock-data': + times = np.arange(tshift,tend+10,0.1) + + nm_mock = parser.get('rd-mock-parameters','nm_mock') + nm_mock = np.int(nm_mock) + mf = parser.get('rd-mock-parameters','mf') + mf = np.float(mf) + af = np.float(parser.get('rd-mock-parameters','af')) + af = np.float(af) + + rdown=rd.Ringdown_Spectrum(mf,af,2,2,n=nm_mock,s=-2,time=times) + + w_mock=np.empty(nm_mock+1) + tau_mock=np.empty(nm_mock+1) + amp_mock=np.empty(nm_mock+1) + ph_mock=np.empty(nm_mock+1) + + for i in range(nm_mock+1): + wp_mock = parser.get('rd-mock-parameters','w'+str(i)) + w_mock[i] = np.float(wp_mock) + tp_mock=parser.get('rd-mock-parameters','tau'+str(i)) + tau_mock[i] = np.float(tp_mock) + amp_mockp = parser.get('rd-mock-parameters','amp'+str(i)) + amp_mock[i] = np.float(amp_mockp) + ph_mockp=parser.get('rd-mock-parameters','phase'+str(i)) + ph_mock[i] = np.float(ph_mockp) + + + pars = np.concatenate((w_mock,tau_mock,amp_mock,ph_mock)) + gw_data=rdown.rd_model_wtau(pars) + + return np.stack((times,gw_data)).T + +def nr_resize(data_1,data_2,tshift=0,tend=100): + times_1 = data_1[:,0].real + times_2 = data_2[:,0].real + data_1_re = data_1[:,1].real + data_1_im = data_1[:,1].imag + data_2_re = data_2[:,1].real + data_2_im = data_2[:,1].imag + + gwnew_re = interpolate.interp1d(times_1, data_1_re, kind = 'cubic') + gwnew_im = interpolate.interp1d(times_1, data_1_im, kind = 'cubic') + gwnew_re5 = interpolate.interp1d(times_2, data_2_re, kind = 'cubic') + gwnew_im5 = interpolate.interp1d(times_2, data_2_im, kind = 'cubic') + + if times_2[-1]>= times_1[-1]: + times_rd = times_1 + else: + times_rd = times_2 + + gwdatanew_re = gwnew_re(times_rd) + gwdatanew_im = gwnew_im(times_rd) + gwdatanew_re5 = gwnew_re5(times_rd) + gwdatanew_im5 = gwnew_im5(times_rd) + gwdatanew = gwdatanew_re + 1j*gwdatanew_im + gwdatanew5 = gwdatanew_re5 + 1j*gwdatanew_im5 + + position_in = np.argmax(times_rd >= tshift) + position_end = np.argmax(times_rd >= tend) + times_rd = times_rd[position_in:position_end] + gwdatanew = gwdatanew[position_in:position_end] + gwdatanew5 = gwdatanew5[position_in:position_end] + + return(np.stack((times_rd,gwdatanew)).T,np.stack((times_rd,gwdatanew5)).T) + + +def phase_align(data_1,data_2,t_align=0): + + #timesrd_final = data_1[:,0] + #phas = np.angle(data_1[:,1]) + #phas = np.unwrap(phas) + #phas5 = np.angle(data_2[:,1]) + #phas5 = np.unwrap(phas5) + #position = np.argmax(timesrd_final >= (t_align)) + #dphase = phas5[position]-phas[position] + + #gwdatanew = data_1[:,1]*np.exp(1j*dphase) + + + phas = np.angle(data_1[:,1]) + phas = np.unwrap(phas) + phas5 = np.angle(data_2[:,1]) + phas5 = np.unwrap(phas5) + position = np.argmax(data_1[:,0] >= (0)) + dphase = phas5[position]-phas[position] + gwdatanew = data_1[:,1]*np.exp(1j*dphase) + timesrd_final = data_1[:,0] + + return np.stack((timesrd_final,gwdatanew)).T + +def create_output_files(output_folder,pars,file_type): + sim_num, model, nmax, tshift, npoints = pars + + """ + Generate the output files you want to export the data to. + file_type must be one of this options: [corner_plot,corner_plot_extra,diagnosis,fit,post_samples,sampler_results,log_z] + """ + + if file_type=='corner_plot': + outfile = output_folder+'/Dynesty_'+str(sim_num)+'_'+model+'_nmax_'+str(nmax)+'_tshift_'+str(tshift)+'_'+str(npoints)+'corner_plot.png' + elif file_type=='corner_plot_extra': + outfile = output_folder+'/Dynesty_'+str(sim_num)+'_'+model+'_nmax_'+str(nmax)+'_tshift_'+str(tshift)+'_'+str(npoints)+'corner_plot_extra.png' + elif file_type=='diagnosis': + outfile = output_folder+'/Dynesty_diagnosis'+str(sim_num)+'_'+model+'_nmax_'+str(nmax)+'_tshift_'+str(tshift)+'_'+str(npoints)+'.png' + elif file_type=='fit': + outfile = output_folder+'/Fit_results_'+str(sim_num)+'tshift_'+str(tshift)+'_'+model+'_nmax_'+str(nmax)+'.png' + elif file_type=='post_samples': + outfile = output_folder+'/posterior_samples-'+str(sim_num)+'tshift_'+str(tshift)+'_'+model+'_nmax_'+str(nmax)+'.csv' + elif file_type=='sampler_results': + outfile = output_folder+'/results_'+str(sim_num)+'tshift_'+str(tshift)+'_'+model+'_nmax_'+str(nmax)+'.pkl' + elif file_type=='log_z': + outfile = output_folder+'/summary'+str(sim_num)+'_'+model+'_nmax_'+str(nmax)+'.csv' + elif file_type=='best_vals': + outfile = output_folder+'/best_values_'+str(sim_num)+'_'+model+'_nmax_'+str(nmax)+'.csv' + else: + print ('Something went wrong') + return + + return outfile + +def read_config_file(parser): + # Setup path and output folders + rootpath=parser.get('nr-paths','rootpath') + simulation_path_1 = parser.get('nr-paths','simulation_path_1') + + if parser.get('nr-paths','simulation_path_2'): + simulation_path_2 = parser.get('nr-paths','simulation_path_2') + else: + simulation_path_2 = simulation_path_1 + + metadata_file = parser.get('nr-paths','metadata_json') + simulation_number = parser.get('nr-paths','simulation_number') + simulation_number = np.int(simulation_number) + + output_folder = parser.get('output-folder','output-folder') + if parser.has_option('setup','export'): + export=eval(parser.get('setup','export')) + else: + export=True + + # Setup sampler and output options + overwrite = eval(parser.get('setup','overwrite')) + downfactor = np.int(parser.get('setup','plot_down_factor')) + sampler = parser.get('setup','sampler') + nr_code = parser.get('setup','nr_code') + if parser.has_option('setup','nb_cores'): + nbcores = np.int(parser.get('setup','nb_cores')) + else: + nbcores = 1 + + # time shift , end and align options + tshift=parser.get('time-setup','tshift') + tshift = np.float(tshift) + + tend=parser.get('time-setup','tend') + tend = np.float(tend) + + t_align=parser.get('time-setup','t_align') + t_align = np.float(t_align) + + # n-tones & nlive points + nmax=parser.get('n-tones','nmax') + nmax = np.int(nmax) + + npoints=parser.get('n-live-points','npoints') + npoints = np.int(npoints) + + # setup the RD model + model=parser.get('rd-model','model') + error_str = eval(parser.get('rd-model','error_str')) + fitnoise=eval(parser.get('rd-model','fit_noise')) + if fitnoise: + l_int=1 + index_mass=-3 + index_spin=-2 + # prior_dim = len(priors_min) + else: + index_mass=-2 + index_spin=-1 + l_int=0 + + if error_str: + error_val=np.float(parser.get('rd-model','error_val')) + if error_val==0: + error_type='' + else: + error_type=error_val + else: + error_type='False' + error_val =0 + + if nr_code == 'SXS': + metadata = {} + with open(metadata_file) as file: + metadata = json.load(file) + af = metadata['remnant_dimensionless_spin'][-1] + mf = metadata['remnant_mass'] + else: + mf = parser.get('rd-mock-parameters','mf') + mf = np.float(mf) + af = np.float(parser.get('rd-mock-parameters','af')) + af = np.float(af) + + if model == 'w-q': + tau_var_str='q' + else: + tau_var_str='tau' + + if nr_code == 'Mock-data': + nm_mock = int(parser.get('rd-mock-parameters','nm_mock')) + else: + nm_mock = None + + res = simulation_path_1,simulation_path_2, metadata_file , simulation_number, output_folder, export, overwrite, sampler,nr_code, nbcores,tshift,tend,t_align, nmax , npoints, model, error_str, fitnoise, l_int, index_mass,index_spin, error_type, error_val, af, mf,tau_var_str,nm_mock + return res \ No newline at end of file diff --git a/code_new/RD_Dynesty_Fits/RD_Dynesty_Fits/RD_Dynesty_Fits.py b/code_new/RD_Dynesty_Fits/RD_Dynesty_Fits/RD_Dynesty_Fits.py new file mode 100755 index 0000000000000000000000000000000000000000..a8d13aac0567fe30ada2a645e23ee07072da0079 --- /dev/null +++ b/code_new/RD_Dynesty_Fits/RD_Dynesty_Fits/RD_Dynesty_Fits.py @@ -0,0 +1,390 @@ +#!/usr/bin/env python +# coding: utf-8 + +# In[38]: + + +"""Generate ringdown templates in the time and perform parameter estimation on them. +""" + + +# In[1]: + + +#Import relevant modules, import data and all that +import time +import numpy as np +import corner +import matplotlib.pyplot as plt +from matplotlib.ticker import MaxNLocator +from matplotlib import rc +from configparser import ConfigParser +plt.rcParams.update({'font.size': 16.5}) + +from multiprocessing import Pool +import random +import dynesty +from dynesty import plotting as dyplot +from dynesty.utils import resample_equal +from dynesty import utils as dyfunc +import os +import argparse +import scipy.optimize as optimization +from scipy.optimize import minimize +import rdown as rd +import rdown_pe as rd_pe +import rdown_utilities as rd_ut +import read_data as rdata + + +# In[2]: + + +## Loading and running data tested with NR data +## Loading and running data tested with Mock data + + +# In[3]: + + +# Cell that calls the arguments from your 'config.ini' file. +try: + parser = argparse.ArgumentParser(description="Simple argument parser") + parser.add_argument("-c", action="store", dest="config_file") + result = parser.parse_args() + config_file=result.config_file + parser = ConfigParser() + parser.read(config_file) + parser.sections() +except SystemExit: + parser = ConfigParser() + parser.read('./run_0_mock/config_n0_to_1_mock.ini') + parser.sections() + pass + + +# In[4]: + + +# Load variables from config file +(simulation_path_1,simulation_path_2, metadata_file , simulation_number, output_folder, + export, overwrite, sampler,nr_code, nbcores,tshift,tend,t_align, + nmax , npoints, model, error_str, fitnoise, l_int, index_mass,index_spin, +error_type, error_val, af, mf,tau_var_str,nm_mock)=rdata.read_config_file(parser) + + +# In[5]: + + +# Show configuration options +dim = nmax+1 +ndim = 4*dim +numbins = 32 #corner plot parameter - how many bins you want + +print('model:',model) +print('nmax:',nmax) +print('nm_mock:',nm_mock) +print('tshift:',tshift) +print('error:', error_str) +print('error value:',error_val) +print('export:',export) +print('nr code:',nr_code) +print('fit noise:',fitnoise) + + +# In[6]: + + +# Create output directories +if not os.path.exists(output_folder): + os.mkdir(output_folder) + print("Directory " , output_folder , " Created ") + +if nr_code == 'Mock-data': + nm_mock_str = 'rec_with'+parser.get('rd-mock-parameters','nm_mock')+'_' +else: + nm_mock_str='' + +if error_str: + output_folder_1=(output_folder+'/'+model+'-nmax'+str(nmax)+'_'+nm_mock_str+str(error_str)+'_'+str(error_type)+'_fitnoise_'+str(fitnoise)) +else: + output_folder_1=output_folder+'/'+model+'-nmax'+str(nmax)+'_'+nm_mock_str+str(error_str)+'_'+'fitnoise_'+str(fitnoise) + +if not os.path.exists(output_folder_1): + os.mkdir(output_folder_1) + print("Directory " , output_folder_1 , " Created ") + + +# In[7]: + + +# Define output files +pars = [simulation_number,model,nmax,tshift,npoints] +corner_plot = rdata.create_output_files(output_folder_1,pars,'corner_plot') +corner_plot_extra = rdata.create_output_files(output_folder_1,pars,'corner_plot_extra') +diagnosis_plot = rdata.create_output_files(output_folder_1,pars,'diagnosis') +fit_plot = rdata.create_output_files(output_folder_1,pars,'fit') +samples_file = rdata.create_output_files(output_folder_1,pars,'post_samples') +results_file = rdata.create_output_files(output_folder_1,pars,'sampler_results') +sumary_data = rdata.create_output_files(output_folder_1,pars,'log_z') +best_data = rdata.create_output_files(output_folder_1,pars,'best_vals') + +files = [corner_plot,corner_plot_extra,diagnosis_plot,fit_plot,samples_file,results_file,sumary_data,best_data] + + +# In[8]: + + +# Remove old files if overwrite = True +if overwrite: + rd_ut.rm_files(files) + + +# In[46]: + + +#Load NR data, align in time and resize. Plot real part and amplitude. Finally compute the mismatch and the snr estimate +data = rdata.read_data(nr_code,simulation_path_1,RD=True,tshift=tshift,tend = tend,metadata_file=metadata_file,parser=parser) +data_l = rdata.read_data(nr_code,simulation_path_2,RD=True,tshift=tshift,tend = tend,metadata_file=metadata_file,parser=parser) +data_r, data_lr = rdata.nr_resize(data,data_l,tshift=tshift,tend=tend) +times_rd = data_r[:,0] + +plt.figure(figsize = (12, 8)) +plt.plot(times_rd, data_r[:,1].real, "r", alpha=0.3, lw=3, label=r'$Lev6$: real') +plt.plot(times_rd, np.sqrt((data_r[:,1].real)**2+(data_r[:,1].imag)**2), "r", alpha=0.3, lw=3, label=r'$Lev5\,amp$') +plt.plot(times_rd, data_lr[:,1].real, "b", alpha=0.3, lw=3, label=r'$Lev5: real$') +plt.plot(times_rd, np.sqrt((data_lr[:,1].real)**2+(data_lr[:,1].imag)**2), "b", alpha=0.3, lw=3, label=r'$Lev5\,amp$') +if error_str and error_val==0: + error = np.sqrt(data_r[:,1]*data_r[:,1]-2*data_r[:,1]*data_lr[:,1]+data_lr[:,1]*data_lr[:,1]) + error_est=np.sqrt(error.imag**2+error.real**2) + plt.plot(times_rd, error_est, "g", alpha=0.3, lw=2, label='error') +plt.legend() + +mismatch=1-rd_ut.EasyMatchT(times_rd,data_r[:,1],data_lr[:,1],tshift,tend) +error=np.sqrt(2*mismatch) +print('error estimate:',error) +print('mismatch:', mismatch) +print('snr:', rd_ut.EasySNRT(times_rd,data_r[:,1],data_lr[:,1],tshift,tend)/error**2) + + +# In[47]: + + +# Phase alignement +if parser.has_option('rd-model','phase_alignment'): + phase_alignment=eval(parser.get('rd-model','phase_alignment')) +else: + phase_alignment=False + +if phase_alignment: + datar_al = rdata.phase_align(data_r,data_lr) + gwdatanew5 = data_lr[:,1] + gwdatanew = datar_al[:,1] + timesrd_final = datar_al[:,0] + mismatch=1-rd_ut.EasyMatchT(timesrd_final,gwdatanew,gwdatanew5,tshift,tend) + error=np.sqrt(2*mismatch) + print('error estimate:',error) + print('mismatch:', mismatch) + print('snr:', rd_ut.EasySNRT(timesrd_final,gwdatanew,gwdatanew5,tshift,tend)/error) + if error_str: + error = np.sqrt(gwdatanew*gwdatanew-2*gwdatanew*gwdatanew5+gwdatanew5*gwdatanew5) + error_est=np.sqrt(error.imag**2+error.real**2) + else : + error = 1 +else: + datar_al = data_r + timesrd_final = datar_al[:,0] + +#Test the new interpolated data +if error_str and error_val==0: + plt.figure(figsize = (12, 8)) + plt.plot(timesrd_final, datar_al[:,1].real, "r", alpha=0.3, lw=2, label='Original') + plt.plot(timesrd_final, data_lr[:,1].real, "b", alpha=0.3, lw=2, label='Aligned') + plt.plot(timesrd_final, error_est, "b", alpha=0.3, lw=2, label='error') + plt.legend() + + +# In[48]: + + +# Define your noise depending on the noise configuration. Load priors and setup the likelihood with rd_pe.Ringdown_PE. +if error_str and error_val==0: + error_final = error_est + norm_factor = 100*len(error_final)/2*np.log(2*np.pi) +elif error_str and error_val!=0: + datar_al[:,1]+=random.uniform(0, error_val) + datar_al[:,1]+=1j*random.uniform(0, error_val) + error_tsh = error_val + error_final=(error_tsh.real**2+error_tsh.imag**2) + norm_factor = 0 +else: + error_tsh=1 + error_final=(error_tsh.real**2+error_tsh.imag**2) + norm_factor = 0 + +priors = rd_pe.load_priors(model,parser,nmax,fitnoise=fitnoise) +rdown=rd.Ringdown_Spectrum(mf,af,2,2,n=nmax,s=-2,time=timesrd_final) +rdown_pe = rd_pe.Ringdown_PE(rdown,datar_al,dim,priors,errors2=error_final,norm_factor=norm_factor,model=model,l_int=l_int) + + +# In[49]: + + +# Get a first estimate by trying to fit the data. +nll = lambda *args: -rdown_pe.log_likelihood(*args) +if model == 'w-tau-fixed-m-af': + if fitnoise: + initial = np.concatenate((np.ones(2*dim),[0.8,0.9,1])) + soln = minimize(nll, initial,bounds=priors) + vars_ml=soln.x + else: + initial = np.concatenate((np.ones(2*dim),[0.8,0.9])) + soln = minimize(nll, initial,bounds=priors) + vars_ml=soln.x +elif model == 'w-tau-fixed': + if fitnoise: + initial = np.concatenate((np.ones(2*dim),[0.2])) + soln = minimize(nll, initial,bounds=priors) + vars_ml=soln.x + else: + initial = np.ones(2*dim) + soln = minimize(nll, initial,bounds=priors) + vars_ml=soln.x +else: + if fitnoise: + initial = np.concatenate((np.ones(ndim),[1])) + soln = minimize(nll, initial,bounds=priors) + vars_ml=soln.x + else: + initial = np.ones(ndim) + soln = minimize(nll, initial,bounds=priors) + vars_ml=soln.x +print("best fit pars from fit: ",vars_ml) + + +# In[50]: + + +mypool = Pool(nbcores) +mypool.size = nbcores + +start = time.process_time() +f2=dynesty.NestedSampler(rdown_pe.log_likelihood,rdown_pe.prior_transform, len(priors), nlive=npoints,sample=sampler,pool=mypool) +if parser.has_option('setup','dlogz'): + dlogz=np.float(parser.get('setup','dlogz')) + f2.run_nested(dlogz=dlogz,print_progress=False) +else: + f2.run_nested(print_progress=False) + +print(time.process_time() - start) + + +# In[52]: + + +res = f2.results +res.samples_u.shape +res.summary() +samps=f2.results.samples +postsamps = rd_ut.posterior_samples(f2) +samps_tr=np.transpose(samps) +half_points=int(round((len(samps_tr[0])/1.25))) +evidence = res.logz[-1] +evidence_error = res.logzerr[-1] +if export: + rd_ut.save_object(res, results_file) + + +# In[53]: + + +pars = nmax,model,samps_tr, half_points +npamps = rd_ut.get_best_amps(pars,parser=parser,nr_code=nr_code) + + +# In[54]: + + +if export: + pars = simulation_number, nmax, tshift, evidence, evidence_error + rd_ut.export_logz_files(sumary_data,pars) + + +# In[55]: + + +labels = rd_ut.define_labels(dim,model,fitnoise) +if export: + pars = tshift, len(priors), labels + rd_ut.export_bestvals_files(best_data,postsamps,pars) + + +# In[56]: + + +w, tau = rdown.QNM_spectrum() +pars = w, tau, mf, af, npamps +truths = rd_ut.get_truths(model,pars,fitnoise) + + +# In[57]: + + +fg=corner.corner(postsamps,quantiles=[0.05,0.5,0.95],show_titles=True,max_n_ticks = 4,bins=50,truths=truths,labels=labels,truth_color='red') +plt.show() +if export: + fg.savefig(corner_plot, format = 'png', bbox_inches = 'tight') + + +# In[58]: + + +from importlib import reload +reload(rd_ut) +if model == 'w-tau-fixed-m-af' and export == True: + truths=np.concatenate((w,tau)) + labels_mf = np.concatenate((w_lab,tau_lab)) + new_samples = rd_ut.convert_m_af_2_w_tau_post(res,fitnoise=False) + figure = corner.corner(new_samples,truths=truths,quantiles=[0.05,0.95],labels=labels_mf,smooth=True,color='b',truth_color='r',show_titles=True) + figure.savefig(corner_plot_extra, format = 'png', bbox_inches = 'tight') + + +# In[151]: + + +#lnz_truth = ndim * -np.log(2 * 10.) # analytic evidence solution +fig, axes = dyplot.runplot(res) +fig.tight_layout() +if export: + fig.savefig(diagnosis_plot, format = 'png', dpi = 384, bbox_inches = 'tight') + + +# In[166]: + + +if export: + dict = {'w-tau':rdown.rd_model_wtau , 'w-q': rdown.rd_model_wq, 'w-tau-fixed':rdown.rd_model_wtau_fixed,'w-tau-fixed-m-af': rdown.rd_model_wtau_m_af} + figband = plt.figure(figsize = (12, 9)) + plt.plot(datar_al[:,0].real,datar_al[:,1].real, "green", alpha=0.9, lw=3, label=r'$res_{240}$') + onesig_bounds = np.array([np.percentile(postsamps[:, i], [5, 95]) for i in range(len(postsamps[0]))]).T + samples_1sigma = filter(lambda sample: np.all(onesig_bounds[0] <= sample) and np.all(sample <= onesig_bounds[1]), postsamps) + samples_1sigma_down = list(samples_1sigma)[::downfactor] + for sample in samples_1sigma_down: + plt.plot(datar_al[:,0].real, dict[model](sample).real, "r-", alpha=0.1, lw=1) + plt.title(r'Comparison of the MC fit data and the $1-\sigma$ error band') + plt.legend() + plt.xlabel('t') + plt.ylabel('h') + plt.show() + figband.savefig(fit_plot) + + +# In[162]: + + +if export: + with open(samples_file,'w') as file: + writer = csv.writer(file) + writer.writerow(labels) + writer.writerows(samps[::downfactor]) + diff --git a/code_new/RD_Dynesty_Fits/RD_Dynesty_Fits/RD_Fits.py b/code_new/RD_Dynesty_Fits/RD_Dynesty_Fits/RD_Fits.py new file mode 100755 index 0000000000000000000000000000000000000000..a8d13aac0567fe30ada2a645e23ee07072da0079 --- /dev/null +++ b/code_new/RD_Dynesty_Fits/RD_Dynesty_Fits/RD_Fits.py @@ -0,0 +1,390 @@ +#!/usr/bin/env python +# coding: utf-8 + +# In[38]: + + +"""Generate ringdown templates in the time and perform parameter estimation on them. +""" + + +# In[1]: + + +#Import relevant modules, import data and all that +import time +import numpy as np +import corner +import matplotlib.pyplot as plt +from matplotlib.ticker import MaxNLocator +from matplotlib import rc +from configparser import ConfigParser +plt.rcParams.update({'font.size': 16.5}) + +from multiprocessing import Pool +import random +import dynesty +from dynesty import plotting as dyplot +from dynesty.utils import resample_equal +from dynesty import utils as dyfunc +import os +import argparse +import scipy.optimize as optimization +from scipy.optimize import minimize +import rdown as rd +import rdown_pe as rd_pe +import rdown_utilities as rd_ut +import read_data as rdata + + +# In[2]: + + +## Loading and running data tested with NR data +## Loading and running data tested with Mock data + + +# In[3]: + + +# Cell that calls the arguments from your 'config.ini' file. +try: + parser = argparse.ArgumentParser(description="Simple argument parser") + parser.add_argument("-c", action="store", dest="config_file") + result = parser.parse_args() + config_file=result.config_file + parser = ConfigParser() + parser.read(config_file) + parser.sections() +except SystemExit: + parser = ConfigParser() + parser.read('./run_0_mock/config_n0_to_1_mock.ini') + parser.sections() + pass + + +# In[4]: + + +# Load variables from config file +(simulation_path_1,simulation_path_2, metadata_file , simulation_number, output_folder, + export, overwrite, sampler,nr_code, nbcores,tshift,tend,t_align, + nmax , npoints, model, error_str, fitnoise, l_int, index_mass,index_spin, +error_type, error_val, af, mf,tau_var_str,nm_mock)=rdata.read_config_file(parser) + + +# In[5]: + + +# Show configuration options +dim = nmax+1 +ndim = 4*dim +numbins = 32 #corner plot parameter - how many bins you want + +print('model:',model) +print('nmax:',nmax) +print('nm_mock:',nm_mock) +print('tshift:',tshift) +print('error:', error_str) +print('error value:',error_val) +print('export:',export) +print('nr code:',nr_code) +print('fit noise:',fitnoise) + + +# In[6]: + + +# Create output directories +if not os.path.exists(output_folder): + os.mkdir(output_folder) + print("Directory " , output_folder , " Created ") + +if nr_code == 'Mock-data': + nm_mock_str = 'rec_with'+parser.get('rd-mock-parameters','nm_mock')+'_' +else: + nm_mock_str='' + +if error_str: + output_folder_1=(output_folder+'/'+model+'-nmax'+str(nmax)+'_'+nm_mock_str+str(error_str)+'_'+str(error_type)+'_fitnoise_'+str(fitnoise)) +else: + output_folder_1=output_folder+'/'+model+'-nmax'+str(nmax)+'_'+nm_mock_str+str(error_str)+'_'+'fitnoise_'+str(fitnoise) + +if not os.path.exists(output_folder_1): + os.mkdir(output_folder_1) + print("Directory " , output_folder_1 , " Created ") + + +# In[7]: + + +# Define output files +pars = [simulation_number,model,nmax,tshift,npoints] +corner_plot = rdata.create_output_files(output_folder_1,pars,'corner_plot') +corner_plot_extra = rdata.create_output_files(output_folder_1,pars,'corner_plot_extra') +diagnosis_plot = rdata.create_output_files(output_folder_1,pars,'diagnosis') +fit_plot = rdata.create_output_files(output_folder_1,pars,'fit') +samples_file = rdata.create_output_files(output_folder_1,pars,'post_samples') +results_file = rdata.create_output_files(output_folder_1,pars,'sampler_results') +sumary_data = rdata.create_output_files(output_folder_1,pars,'log_z') +best_data = rdata.create_output_files(output_folder_1,pars,'best_vals') + +files = [corner_plot,corner_plot_extra,diagnosis_plot,fit_plot,samples_file,results_file,sumary_data,best_data] + + +# In[8]: + + +# Remove old files if overwrite = True +if overwrite: + rd_ut.rm_files(files) + + +# In[46]: + + +#Load NR data, align in time and resize. Plot real part and amplitude. Finally compute the mismatch and the snr estimate +data = rdata.read_data(nr_code,simulation_path_1,RD=True,tshift=tshift,tend = tend,metadata_file=metadata_file,parser=parser) +data_l = rdata.read_data(nr_code,simulation_path_2,RD=True,tshift=tshift,tend = tend,metadata_file=metadata_file,parser=parser) +data_r, data_lr = rdata.nr_resize(data,data_l,tshift=tshift,tend=tend) +times_rd = data_r[:,0] + +plt.figure(figsize = (12, 8)) +plt.plot(times_rd, data_r[:,1].real, "r", alpha=0.3, lw=3, label=r'$Lev6$: real') +plt.plot(times_rd, np.sqrt((data_r[:,1].real)**2+(data_r[:,1].imag)**2), "r", alpha=0.3, lw=3, label=r'$Lev5\,amp$') +plt.plot(times_rd, data_lr[:,1].real, "b", alpha=0.3, lw=3, label=r'$Lev5: real$') +plt.plot(times_rd, np.sqrt((data_lr[:,1].real)**2+(data_lr[:,1].imag)**2), "b", alpha=0.3, lw=3, label=r'$Lev5\,amp$') +if error_str and error_val==0: + error = np.sqrt(data_r[:,1]*data_r[:,1]-2*data_r[:,1]*data_lr[:,1]+data_lr[:,1]*data_lr[:,1]) + error_est=np.sqrt(error.imag**2+error.real**2) + plt.plot(times_rd, error_est, "g", alpha=0.3, lw=2, label='error') +plt.legend() + +mismatch=1-rd_ut.EasyMatchT(times_rd,data_r[:,1],data_lr[:,1],tshift,tend) +error=np.sqrt(2*mismatch) +print('error estimate:',error) +print('mismatch:', mismatch) +print('snr:', rd_ut.EasySNRT(times_rd,data_r[:,1],data_lr[:,1],tshift,tend)/error**2) + + +# In[47]: + + +# Phase alignement +if parser.has_option('rd-model','phase_alignment'): + phase_alignment=eval(parser.get('rd-model','phase_alignment')) +else: + phase_alignment=False + +if phase_alignment: + datar_al = rdata.phase_align(data_r,data_lr) + gwdatanew5 = data_lr[:,1] + gwdatanew = datar_al[:,1] + timesrd_final = datar_al[:,0] + mismatch=1-rd_ut.EasyMatchT(timesrd_final,gwdatanew,gwdatanew5,tshift,tend) + error=np.sqrt(2*mismatch) + print('error estimate:',error) + print('mismatch:', mismatch) + print('snr:', rd_ut.EasySNRT(timesrd_final,gwdatanew,gwdatanew5,tshift,tend)/error) + if error_str: + error = np.sqrt(gwdatanew*gwdatanew-2*gwdatanew*gwdatanew5+gwdatanew5*gwdatanew5) + error_est=np.sqrt(error.imag**2+error.real**2) + else : + error = 1 +else: + datar_al = data_r + timesrd_final = datar_al[:,0] + +#Test the new interpolated data +if error_str and error_val==0: + plt.figure(figsize = (12, 8)) + plt.plot(timesrd_final, datar_al[:,1].real, "r", alpha=0.3, lw=2, label='Original') + plt.plot(timesrd_final, data_lr[:,1].real, "b", alpha=0.3, lw=2, label='Aligned') + plt.plot(timesrd_final, error_est, "b", alpha=0.3, lw=2, label='error') + plt.legend() + + +# In[48]: + + +# Define your noise depending on the noise configuration. Load priors and setup the likelihood with rd_pe.Ringdown_PE. +if error_str and error_val==0: + error_final = error_est + norm_factor = 100*len(error_final)/2*np.log(2*np.pi) +elif error_str and error_val!=0: + datar_al[:,1]+=random.uniform(0, error_val) + datar_al[:,1]+=1j*random.uniform(0, error_val) + error_tsh = error_val + error_final=(error_tsh.real**2+error_tsh.imag**2) + norm_factor = 0 +else: + error_tsh=1 + error_final=(error_tsh.real**2+error_tsh.imag**2) + norm_factor = 0 + +priors = rd_pe.load_priors(model,parser,nmax,fitnoise=fitnoise) +rdown=rd.Ringdown_Spectrum(mf,af,2,2,n=nmax,s=-2,time=timesrd_final) +rdown_pe = rd_pe.Ringdown_PE(rdown,datar_al,dim,priors,errors2=error_final,norm_factor=norm_factor,model=model,l_int=l_int) + + +# In[49]: + + +# Get a first estimate by trying to fit the data. +nll = lambda *args: -rdown_pe.log_likelihood(*args) +if model == 'w-tau-fixed-m-af': + if fitnoise: + initial = np.concatenate((np.ones(2*dim),[0.8,0.9,1])) + soln = minimize(nll, initial,bounds=priors) + vars_ml=soln.x + else: + initial = np.concatenate((np.ones(2*dim),[0.8,0.9])) + soln = minimize(nll, initial,bounds=priors) + vars_ml=soln.x +elif model == 'w-tau-fixed': + if fitnoise: + initial = np.concatenate((np.ones(2*dim),[0.2])) + soln = minimize(nll, initial,bounds=priors) + vars_ml=soln.x + else: + initial = np.ones(2*dim) + soln = minimize(nll, initial,bounds=priors) + vars_ml=soln.x +else: + if fitnoise: + initial = np.concatenate((np.ones(ndim),[1])) + soln = minimize(nll, initial,bounds=priors) + vars_ml=soln.x + else: + initial = np.ones(ndim) + soln = minimize(nll, initial,bounds=priors) + vars_ml=soln.x +print("best fit pars from fit: ",vars_ml) + + +# In[50]: + + +mypool = Pool(nbcores) +mypool.size = nbcores + +start = time.process_time() +f2=dynesty.NestedSampler(rdown_pe.log_likelihood,rdown_pe.prior_transform, len(priors), nlive=npoints,sample=sampler,pool=mypool) +if parser.has_option('setup','dlogz'): + dlogz=np.float(parser.get('setup','dlogz')) + f2.run_nested(dlogz=dlogz,print_progress=False) +else: + f2.run_nested(print_progress=False) + +print(time.process_time() - start) + + +# In[52]: + + +res = f2.results +res.samples_u.shape +res.summary() +samps=f2.results.samples +postsamps = rd_ut.posterior_samples(f2) +samps_tr=np.transpose(samps) +half_points=int(round((len(samps_tr[0])/1.25))) +evidence = res.logz[-1] +evidence_error = res.logzerr[-1] +if export: + rd_ut.save_object(res, results_file) + + +# In[53]: + + +pars = nmax,model,samps_tr, half_points +npamps = rd_ut.get_best_amps(pars,parser=parser,nr_code=nr_code) + + +# In[54]: + + +if export: + pars = simulation_number, nmax, tshift, evidence, evidence_error + rd_ut.export_logz_files(sumary_data,pars) + + +# In[55]: + + +labels = rd_ut.define_labels(dim,model,fitnoise) +if export: + pars = tshift, len(priors), labels + rd_ut.export_bestvals_files(best_data,postsamps,pars) + + +# In[56]: + + +w, tau = rdown.QNM_spectrum() +pars = w, tau, mf, af, npamps +truths = rd_ut.get_truths(model,pars,fitnoise) + + +# In[57]: + + +fg=corner.corner(postsamps,quantiles=[0.05,0.5,0.95],show_titles=True,max_n_ticks = 4,bins=50,truths=truths,labels=labels,truth_color='red') +plt.show() +if export: + fg.savefig(corner_plot, format = 'png', bbox_inches = 'tight') + + +# In[58]: + + +from importlib import reload +reload(rd_ut) +if model == 'w-tau-fixed-m-af' and export == True: + truths=np.concatenate((w,tau)) + labels_mf = np.concatenate((w_lab,tau_lab)) + new_samples = rd_ut.convert_m_af_2_w_tau_post(res,fitnoise=False) + figure = corner.corner(new_samples,truths=truths,quantiles=[0.05,0.95],labels=labels_mf,smooth=True,color='b',truth_color='r',show_titles=True) + figure.savefig(corner_plot_extra, format = 'png', bbox_inches = 'tight') + + +# In[151]: + + +#lnz_truth = ndim * -np.log(2 * 10.) # analytic evidence solution +fig, axes = dyplot.runplot(res) +fig.tight_layout() +if export: + fig.savefig(diagnosis_plot, format = 'png', dpi = 384, bbox_inches = 'tight') + + +# In[166]: + + +if export: + dict = {'w-tau':rdown.rd_model_wtau , 'w-q': rdown.rd_model_wq, 'w-tau-fixed':rdown.rd_model_wtau_fixed,'w-tau-fixed-m-af': rdown.rd_model_wtau_m_af} + figband = plt.figure(figsize = (12, 9)) + plt.plot(datar_al[:,0].real,datar_al[:,1].real, "green", alpha=0.9, lw=3, label=r'$res_{240}$') + onesig_bounds = np.array([np.percentile(postsamps[:, i], [5, 95]) for i in range(len(postsamps[0]))]).T + samples_1sigma = filter(lambda sample: np.all(onesig_bounds[0] <= sample) and np.all(sample <= onesig_bounds[1]), postsamps) + samples_1sigma_down = list(samples_1sigma)[::downfactor] + for sample in samples_1sigma_down: + plt.plot(datar_al[:,0].real, dict[model](sample).real, "r-", alpha=0.1, lw=1) + plt.title(r'Comparison of the MC fit data and the $1-\sigma$ error band') + plt.legend() + plt.xlabel('t') + plt.ylabel('h') + plt.show() + figband.savefig(fit_plot) + + +# In[162]: + + +if export: + with open(samples_file,'w') as file: + writer = csv.writer(file) + writer.writerow(labels) + writer.writerows(samps[::downfactor]) + diff --git a/code_new/RD_Dynesty_Fits/RD_Dynesty_Fits/__init__.py b/code_new/RD_Dynesty_Fits/RD_Dynesty_Fits/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..8b137891791fe96927ad78e64b0aad7bded08bdc --- /dev/null +++ b/code_new/RD_Dynesty_Fits/RD_Dynesty_Fits/__init__.py @@ -0,0 +1 @@ + diff --git a/code_new/RD_Dynesty_Fits/RD_Dynesty_Fits/rdown.py b/code_new/RD_Dynesty_Fits/RD_Dynesty_Fits/rdown.py new file mode 100644 index 0000000000000000000000000000000000000000..1357ccbf98a454670c79fb49574d7fe1447e243a --- /dev/null +++ b/code_new/RD_Dynesty_Fits/RD_Dynesty_Fits/rdown.py @@ -0,0 +1,208 @@ +# Copyright (C) 2021 Xisco Jimenez Forteza +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + +# +# ============================================================================= +# +# Preamble +# +# ============================================================================= +# +# Module to generate RD waveforms. + +import numpy as np +import qnm +import os + +f_fpars= [[2.95845, -2.58697, 0.0533469], [2.12539, -1.78054, 0.0865503], [1.74755, -1.44776, 0.123666], [1.78287, -1.53203, 0.129475], [2.04028, -1.83224, 0.112497]] +q_fpars=[[0.584077, 1.52053, -0.480658], [0.00561441, 0.630715, -0.432664], [-0.197965, 0.515956, -0.369706], [-0.275097, 0.455691, -0.331543], [-0.287596, 0.398514, -0.309799]] + + +c=2.99792458*10**8;G=6.67259*10**(-11);MS=1.9885*10**30; +class Ringdown_Spectrum: + """RDown model generator""" + def __init__(self,mf,af,l,m,n=4,s=-2,time=[],fixed=False,qnm_model='berti'): + self.mf = mf + self.af = af + self.l = l + self.m = m + self.n = n + self.time = time + self.grav_220 = [qnm.modes_cache(s=s,l=self.l,m=self.m,n=i) for i in range (0,self.n+1)] + self.dim = self.n+1 + self.fixed = fixed + self.qnm_model = qnm_model + dict_omega = {'berti': self.QNM_Berti , 'qnm': self.QNM_spectrum} + dic = {'w-tau':self.rd_model_wtau , 'w-q': self.rd_model_wq, 'w-tau-fixed':self.rd_model_wtau_fixed,'w-tau-fixed-m-af': self.rd_model_wtau_m_af} + + if len(self.time)==0: + self.time = np.arange(0,100,0.1) + + if self.fixed: + omegas_new=np.asarray([self.grav_220[i](a=self.af)[0] for i in range (0,self.dim)]) + self.w = (np.real(omegas_new))/self.mf + self.tau=-1/(np.imag(omegas_new))*self.mf + + + def QNM_spectrum(self): + """ It computes the RD frequencies and damping times in NR units. + """ + omegas_new=np.asarray([self.grav_220[i](a=self.af)[0] for i in range (0,self.n+1)]) + w_m_a = (np.real(omegas_new))/self.mf + tau_m_a=-1/(np.imag(omegas_new))*self.mf + + return (w_m_a, tau_m_a) + + def QNM_Berti(self,rdowndata): + """ It computes the RD frequencies and damping times in NR units. + """ + position=np.argmax(rdowndata[0,0] >= (self.af)) + #w_m_a=f1+f2*(1-af)**f3 + w_m_a=[None]*(self.n+1) + tau_ma_a=[None]*(self.n+1) + + for i in range(self.n+1): + qnm=rdowndata[i,1:3,position] + w_m_a[i] = qnm[0]/self.mf + tau_ma_a[i] = -1/(qnm[1])*self.mf + + return w_m_a, tau_ma_a + + + def w_fpars_Berti(self,n): + return f_fpars[n] + + def tau_qpars_Berti(self,n): + return q_fpars[n] + + def mass_from_wtau(self,n,w,tau): + f1,f2,f3 = w_fpars_Berti(n) + q1,q2,q3 = tau_qpars_Berti(n) + res=(f1 + f2*(2**(-1/q3)*((-2*q1 + w*tau)/q2)**(1/q3))**f3)/w + return res + + def spin_from_wtau(self,n,w,tau): + f1,f2,f3 = w_fpars_Berti(n) + q1,q2,q3 = tau_qpars_Berti(n) + res=1 - 2**(-1/q3)*((-2*q1 + w*tau)/q2)**(1/q3) + return res + + def mass_from_wtau_loop(self,w,tau,l,m): + res=[None]*dim + for n in range (0,dim): + f1,f2,f3 = w_fpars_Berti(n) + q1,q2,q3 = tau_qpars_Berti(n) + res[n]=(f1 + f2*(2**(-1/q3)*((-2*q1 + w[n]*tau[n])/q2)**(1/q3))**f3)/w[n] + return res + + def spin_from_wtau_loop(self,w,tau,l,m): + res=[None]*dim + for n in range (0,dim): + f1,f2,f3 = w_fpars_Berti(n) + q1,q2,q3 = tau_qpars_Berti(n) + res[n]= 1 - 2**(-1/q3)*((-2*q1 + w[n]*tau[n])/q2)**(1/q3) + return res + + + def rd_model_wtau(self,theta): + """RD model parametrized with the damping time tau. + """ + assert int(len(theta)/4) == self.dim, 'Please recheck your n and parameters' + + wvars = theta[ : (self.dim)] + tvars = theta[(self.dim) : 2*(self.dim)] + xvars = theta[2*(self.dim) : 3*(self.dim)] + yvars = theta[3*(self.dim) : ] + + ansatz = 0 + for i in range (0,self.dim): + ansatz += (xvars[i]*np.exp(1j*yvars[i]))*np.exp(-self.time/tvars[i]) * (np.cos(wvars[i]*self.time)-1j*np.sin(wvars[i]*self.time)) + # -1j to agree with SXS convention + return ansatz + + def rd_model_wtau_m_af(theta): + """RD model parametrized with the damping time tau and with the QNM spectrum fixd to GR. The QNM spectrum is given from the mass and spin. + """ + xvars = theta[ : (dim)] + yvars = theta[(dim) : 2*(dim)] + mass_vars = theta[index_mass] + spin_vars = theta[index_spin] + + w_m_a , tau_m_a = dict_omega[self.qnm_model](mass_vars,spin_vars,2,2) + + ansatz = 0 + for i in range (0,dim): + ansatz += (xvars[i]*np.exp(1j*yvars[i]))*np.exp(-timesrd_final_tsh/tau_m_a[i]) * (np.cos(w_m_a[i]*timesrd_final_tsh)-1j*np.sin(w_m_a[i]*timesrd_final_tsh)) + # -1j to agree with SXS convention + return ansatz + + def rd_model_wtau_fixed(theta): + """RD model parametrized with the damping time tau and with the QNM spectrum fixd to GR. + """ + xvars = theta[ : (dim)] + yvars = theta[(dim) : 2*(dim)] + + ansatz = 0 + for i in range (0,dim): + ansatz += (xvars[i]*np.exp(1j*yvars[i]))*np.exp(-timesrd_final_tsh/tau[i]) * (np.cos(w[i]*timesrd_final_tsh)-1j*np.sin(w[i]*timesrd_final_tsh)) + # -1j to agree with SXS convention + return ansatz + + def rd_model_wq(self,theta): + """RD model parametrized with the quality factor q. + """ + assert int(len(theta)/4) == self.dim, 'Please recheck your n and parameters' + + wvars = theta[ : (self.dim)] + qvars = theta[(self.dim) : 2*(self.dim)] + xvars = theta[2*(self.dim) : 3*(self.dim)] + yvars = theta[3*(self.dim) : ] + + ansatz = 0 + for i in range (0,self.dim): + ansatz += (xvars[i]*np.exp(1j*yvars[i]))*np.exp(-self.time*np.pi*wvars[i]/qvars[i])*(np.cos(wvars[i]*self.time)-1j*np.sin(wvars[i]*self.time)) + # -1j to agree with SXS convention + return ansatz + + def rd_model_wq_fixed(self,theta): + """RD model parametrized with the damping time tau and with the QNM spectrum fixd to GR. + """ + xvars = theta[ : (self.dim)] + yvars = theta[(self.dim) : 2*(self.dim)] + + ansatz = 0 + for i in range (0,self.dim): + ansatz += (xvars[i]*np.exp(1j*yvars[i]))*np.exp(-self.time/self.tau[i]) * (np.cos(self.w[i]*self.time)-1j*np.sin(self.w[i]*self.time)) + # -1j to agree with SXS convention + return ansatz + + + def rd_model_wq_m_a(self,theta): + """RD model parametrized with the damping time tau and with the QNM spectrum fixd to GR. The QNM spectrum is given from the mass and spin. + """ + xvars = theta[ : (self.dim)] + yvars = theta[(self.dim) : 2*(self.dim)] + mass_vars = theta[-2] + spin_vars = theta[-1] + + w_m_a , tau_m_a = QNM_spectrum() + + ansatz = 0 + for i in range (0,dim): + ansatz += (xvars[i]*np.exp(1j*yvars[i]))*np.exp(-timesrd_final_tsh/tau_m_a[i]) * (np.cos(w_m_a[i]*timesrd_final_tsh)-1j*np.sin(w_m_a[i]*timesrd_final_tsh)) + # -1j to agree with SXS convention + return ansatz \ No newline at end of file diff --git a/code_new/RD_Dynesty_Fits/RD_Dynesty_Fits/rdown_pe.py b/code_new/RD_Dynesty_Fits/RD_Dynesty_Fits/rdown_pe.py new file mode 100644 index 0000000000000000000000000000000000000000..c92e073cac48d68b9fb46fc44a03b6e1c2c8af65 --- /dev/null +++ b/code_new/RD_Dynesty_Fits/RD_Dynesty_Fits/rdown_pe.py @@ -0,0 +1,191 @@ +# Copyright (C) 2021 Xisco Jimenez Forteza +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + +# +# ============================================================================= +# +# Preamble +# +# ============================================================================= +# +# Module to run PE on RD data +import random +from multiprocessing import Pool +import dynesty +import numpy as np +import rdown + +class Ringdown_PE: + def __init__(self,rdown_fun,data,dim,priors,errors2=1,theta=[],model='w-tau',norm_factor=0,l_int=0): + self.dim = dim + self.rdown_fun = rdown_fun + self.times = data[:,0] + self.datare = data[:,1].real + self.dataim = data[:,1].imag + self.priors = priors + self.priors_min = priors[:,0] + self.priors_max = priors[:,1] + self.prior_dim = len(priors) + self.errors2 = errors2 + self.norm_factor = norm_factor + self.model = model + self.l_int = l_int + self.theta = theta + self.dict = {'w-tau':rdown_fun.rd_model_wtau , 'w-q': rdown_fun.rd_model_wq, 'w-tau-fixed':rdown_fun.rd_model_wtau_fixed,'w-tau-fixed-m-af': rdown_fun.rd_model_wtau_m_af} + + #def log_likelihood(self,theta,sigma=1): + # """chi2 likelihood. + # """ + # modelev = dict[model](theta) + # result = -np.sum(((gwdatanew_re_tsh - modelev.real)**2+(gwdatanew_im_tsh - modelev.imag)**2)/(2*theta[-1]*error_final)) + # if np.isnan(result): + # return -np.inf + # return result + + def log_likelihood(self,theta,sigma=1): + """chi2 likelihood. + """ + modelev = self.dict[self.model](theta) + modelevre= modelev.real + modelevim= modelev.imag + + sigma2 = self.errors2 + self.l_int*(self.datare** 2+self.dataim**2) * np.exp(2 * theta[-1]) + + result = -0.5*np.sum(((self.datare - modelevre)**2+(self.dataim - modelevim)**2)/sigma2+self.l_int*(np.log(2*np.pi*sigma2)))-self.l_int*self.norm_factor + + if np.isnan(result): + return -np.inf + return result + + + def prior_transform(self,cube): + """RD uniform priors. The values for priors_min and priors_max must be given out of this function. + """ + for i in range(self.prior_dim): + cube[i] = self.priors_min[i]+ cube[i]*(self.priors_max[i]-self.priors_min[i]) + return cube + +def load_priors(model,config_parser,nmax,fitnoise=True): + # loading priors + if model == 'w-q': + tau_var_str='q' + else: + tau_var_str='tau' + + if model == 'w-tau': + w_mins=np.empty(nmax+1) + w_maxs=np.empty(nmax+1) + tau_mins=np.empty(nmax+1) + tau_maxs=np.empty(nmax+1) + a_mins=np.empty(nmax+1) + a_maxs=np.empty(nmax+1) + ph_mins=np.empty(nmax+1) + ph_maxs=np.empty(nmax+1) + + for i in range(nmax+1): + wp_min=config_parser.get('prior-w'+str(i),'w'+str(i)+'_min') + w_mins[i] = np.float(wp_min) + + wp_max=config_parser.get('prior-w'+str(i),'w'+str(i)+'_max') + w_maxs[i] = np.float(wp_max) + + taup_min=config_parser.get('prior-'+tau_var_str+str(i),tau_var_str+str(i)+'_min') + tau_mins[i] = np.float(taup_min) + + taup_max=config_parser.get('prior-'+tau_var_str+str(i),tau_var_str+str(i)+'_max') + tau_maxs[i] = np.float(taup_max) + + amp0_min=config_parser.get('prior-amp'+str(i),'amp'+str(i)+'_min') + a_mins[i] = np.float(amp0_min) + + amp1_max=config_parser.get('prior-amp'+str(i),'amp'+str(i)+'_max') + a_maxs[i] = np.float(amp1_max) + + phase_min=config_parser.get('prior-phase'+str(i),'phase'+str(i)+'_min') + ph_mins[i] = np.float(phase_min)*2*np.pi + + phase_max=config_parser.get('prior-phase'+str(i),'phase'+str(i)+'_max') + ph_maxs[i] = np.float(phase_max)*2*np.pi + + priors_min = np.concatenate((w_mins,tau_mins,a_mins,ph_mins)) + priors_max = np.concatenate((w_maxs,tau_maxs,a_maxs,ph_maxs)) + prior_dim = len(priors_min) + priors=np.column_stack((priors_min,priors_max)) + + if model == 'w-tau-fixed': + a_mins=np.empty(nmax+1) + a_maxs=np.empty(nmax+1) + ph_mins=np.empty(nmax+1) + ph_maxs=np.empty(nmax+1) + + for i in range(nmax+1): + amp0_min=config_parser.get('prior-amp'+str(i),'amp'+str(i)+'_min') + a_mins[i] = np.float(amp0_min) + + amp1_max=config_parser.get('prior-amp'+str(i),'amp'+str(i)+'_max') + a_maxs[i] = np.float(amp1_max) + + phase_min=config_parser.get('prior-phase'+str(i),'phase'+str(i)+'_min') + ph_mins[i] = np.float(phase_min)*2*np.pi + + phase_max=config_parser.get('prior-phase'+str(i),'phase'+str(i)+'_max') + ph_maxs[i] = np.float(phase_max)*2*np.pi + + + priors_min = np.concatenate((a_mins,ph_mins)) + priors_max = np.concatenate((a_maxs,ph_maxs)) + prior_dim = len(priors_min) + priors=np.column_stack((priors_min,priors_max)) + + elif model == 'w-tau-fixed-m-af': + a_mins=np.empty(nmax+1) + a_maxs=np.empty(nmax+1) + ph_mins=np.empty(nmax+1) + ph_maxs=np.empty(nmax+1) + + for i in range(nmax+1): + amp0_min=config_parser.get('prior-amp'+str(i),'amp'+str(i)+'_min') + a_mins[i] = np.float(amp0_min) + + amp1_max=config_parser.get('prior-amp'+str(i),'amp'+str(i)+'_max') + a_maxs[i] = np.float(amp1_max) + + phase_min=config_parser.get('prior-phase'+str(i),'phase'+str(i)+'_min') + ph_mins[i] = np.float(phase_min)*2*np.pi + + phase_max=config_parser.get('prior-phase'+str(i),'phase'+str(i)+'_max') + ph_maxs[i] = np.float(phase_max)*2*np.pi + + mass_min=[np.float(config_parser.get('prior-mass','mass_min'))] + mass_max=[np.float(config_parser.get('prior-mass','mass_max'))] + spin_min=[np.float(config_parser.get('prior-spin','spin_min'))] + spin_max=[np.float(config_parser.get('prior-spin','spin_max'))] + priors_min = np.concatenate((a_mins,ph_mins,mass_min,spin_min)) + priors_max = np.concatenate((a_maxs,ph_maxs,mass_max,spin_max)) + prior_dim = len(priors_min) + priors=np.column_stack((priors_min,priors_max)) + + + if fitnoise: + priors_fit_min=[np.float(config_parser.get('prior-noise','noise_min'))] + priors_fit_max=[np.float(config_parser.get('prior-noise','noise_max'))] + priors_min = np.concatenate((priors_min,priors_fit_min)) + priors_max = np.concatenate((priors_max,priors_fit_max)) + priors=np.column_stack((priors_min,priors_max)) + prior_dim = len(priors_min) + + return priors \ No newline at end of file diff --git a/code_new/RD_Dynesty_Fits/RD_Dynesty_Fits/rdown_utilities.py b/code_new/RD_Dynesty_Fits/RD_Dynesty_Fits/rdown_utilities.py new file mode 100644 index 0000000000000000000000000000000000000000..c4a5b95c1c26beb418d2457fbd2a2b09212778c3 --- /dev/null +++ b/code_new/RD_Dynesty_Fits/RD_Dynesty_Fits/rdown_utilities.py @@ -0,0 +1,318 @@ +# Copyright (C) 2021 Xisco Jimenez Forteza +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + +# +# ============================================================================= +# +# Preamble +# +# ============================================================================= +# +# Module to run PE on RD data +import numpy as np +from dynesty.utils import resample_equal +from dynesty import utils as dyfunc +import os +import csv +import pandas as pd +import pickle + +def posterior_samples(sampler): + """ + Returns posterior samples from nested samples and weights + given by dynsety sampler + """ + + dynesty_samples = sampler.results['samples'] + wt = np.exp(sampler.results['logwt'] - + sampler.results['logz'][-1]) + # Make sure that sum of weights equal to 1 + weights = wt/np.sum(wt) + posterior_dynesty = dyfunc.resample_equal(dynesty_samples, weights) + return posterior_dynesty + +def FFT_FreqBins(times): + Len = len(times) + DeltaT = times[-1]- times[0] + dt = DeltaT/(Len-1) + dnu = 1/(Len*dt) + maxfreq = 1/(2*dt) + add = dnu/4 + + p = np.arange(0.0,maxfreq+add,dnu) + m = np.arange(p[-1]-(2*maxfreq)+dnu,-dnu/2+add,dnu) + res=np.concatenate((p,m)) + + return res + +def hFromPsi4FFI(tpsi4,f0): + + timecheck1=tpsi4[-2,0]-tpsi4[-1,0] + timecheck2=tpsi4[1,0]-tpsi4[0,0] + + if np.abs(timecheck1-timecheck2)>=0.0001: + print("The data might not be equally sampled!!") + + times,data= tpsi4[:,0],tpsi4[:,1] + + freqs = FT_FreqBins(xaxis.real).real + position = np.argmax(freqs >= f0) + freqs[:position]=f0*np.ones(len(freqs[:position])) + freqs=2*np.pi*freqs + + fdata=fft(data) + len(myTable)*ifft(- fdata/floor**2); + np.stack((times,data)).T + + +def twopoint_autocovariance(t,n): + """ It computes the two-point autocovariance function. + """ + dt=t[1]-t[0] + res = np.zeros(len(n)) + taus = np.zeros(len(n)) + for tau in range(0,int(len(n)/2)): + ntau=np.roll(n, tau) + taus[tau] = t[tau] + res[tau]=np.sum(n*ntau).real + return (taus[:int(len(n)/2)],res[:int(len(n)/2)]) + +def save_object(obj, filename): + with open(filename, 'wb') as output: # Overwrites any existing file. + pickle.dump(obj, output, pickle.HIGHEST_PROTOCOL) + + +def EasyMatchT(t,h1,h2,tmin,tmax): + """ It computes the time-domain match for (h1|h2) complex waveforms. + """ + pos = np.argmax(t >= (tmin)); + + h1red=h1[pos:]; + h2red=h2[pos:]; + + norm1=np.sum(np.abs(h1red)**2) + norm2=np.sum(np.abs(h2red)**2) + + myTable=h1red*np.conjugate(h2red) + res=((np.sum(myTable)/np.sqrt(norm1*norm2))).real + + return res + +def EasySNRT(t,h1,h2,tmin,tmax): + """ It computes the time-domain snr for (h1|h2) complex waveforms. + """ + pos = np.argmax(t >= (tmin)); + + h1red=h1[pos:]; + h2red=h2[pos:]; + + myTable=h1red*np.conjugate(h2red) + res=2*np.sqrt((np.sum(myTable)).real) + + return res + +def FindTmaximum(y): + """ It determines the maximum absolute value of the complex waveform. + """ + absval = np.sqrt(y[:,1]*y[:,1]+y[:,2]*y[:,2]) + vmax=np.max(absval) + index = np.argmax(absval == vmax) + timemax=y[index,0] + + return timemax + +def export_logz_files(output_file,pars): + sim_num, nmax, tshift, evidence, evidence_error = pars + + """ + Generate the logz.csv files you want to export the data to. + file_type must be one of this options: [corner_plot,corner_plot_extra,diagnosis,fit,post_samples,sampler_results,log_z] + """ + + summary_titles=['n','id','t_shift','dlogz','dlogz_err'] + if os.path.exists(output_file): + outvalues = np.array([[nmax, sim_num, tshift, evidence,evidence_error]]) + else: + outvalues = np.array([summary_titles,[nmax, sim_num, tshift, evidence,evidence_error]]) + + with open(output_file, 'a') as file: + writer = csv.writer(file) + if (outvalues.shape)[0]>1 : + writer.writerows(outvalues) + else: + writer.writerow(outvalues[0]) + + return + +def export_bestvals_files(best_data_file,postsamps,pars): + + tshift, lenpriors, labels = pars + + sigma_vars_m = np.empty(lenpriors) + sigma_vars_p = np.empty(lenpriors) + sigma_vars = np.empty(lenpriors) + sigma_vars_ml = np.empty(lenpriors) + for i in range(lenpriors): + amps_aux = postsamps[:,i] + sigma_vars_m[i] = np.quantile(amps_aux, 0.05) + sigma_vars[i] = np.quantile(amps_aux, 0.5) + sigma_vars_ml[i] = postsamps[-1,i] + sigma_vars_p[i] = np.quantile(amps_aux, 0.95) + + sigma_vars_all = [sigma_vars,sigma_vars_ml,sigma_vars_m,sigma_vars_p] + sigma_vars_all=np.stack([sigma_vars,sigma_vars_ml,sigma_vars_m,sigma_vars_p], axis=0) + + key =['max val','max val ml','lower bound','higher bound'] + dfslist = [pd.DataFrame(np.concatenate(([tshift],sigma_vars_all[i])).reshape((-1,lenpriors+1)), columns=np.concatenate((['tshift'],labels)), index = [key[i]]) for i in range(4)] + df2 = pd.concat(dfslist) + if os.path.exists(best_data_file): + df2.to_csv(best_data_file, mode='a', header=False,index = True) + else: + df2.to_csv(best_data_file, index = True) + + + +def define_labels(dim,model,fitnoise): + wstr = r'$\omega_' + + if model == 'w-tau': + taustr = r'$\tau_' + elif model == 'w-q': + taustr = r'$q_' + elif model == 'w-tau-fixed': + taustr = r'$dumb_var}' + elif model == 'w-tau-fixed-m-af': + taustr = r'$\tau_' + + ampstr = r'$A_' + phasestr = r'$\phi_' + + w_lab = [None] * dim + tau_lab = [None] * dim + amp_lab = [None] * dim + pha_lab = [None] * dim + mass_lab = ['mass'] + spin_lab = ['spin'] + + for i in range(dim): + w_lab[i] = wstr+str(i)+'$' + tau_lab[i] = taustr+str(i)+'$' + amp_lab[i] = ampstr+str(i)+'$' + pha_lab[i] = phasestr+str(i)+'$' + + + labels = np.concatenate((w_lab,tau_lab,amp_lab,pha_lab)) + + if model=='w-tau-fixed': + labels = np.concatenate((amp_lab,pha_lab)) + + if model=='w-tau-fixed-m-af': + pha_lab[i] = phasestr+str(i)+'$' + + labels = np.concatenate((amp_lab,pha_lab,mass_lab,spin_lab)) + + if fitnoise: + noise_lab = ['noise'] + labels = np.concatenate((labels,noise_lab)) + + return labels + +def get_truths(model,pars,fitnoise): + w, tau, mf, af , npamps = pars + if model == 'w-q': + tau_val = np.pi*w*tau + truths = np.concatenate((w,tau_val,npamps)) + elif model == 'w-tau': + tau_val = tau + truths = np.concatenate((w,tau_val,npamps)) + elif model == 'w-tau-fixed': + truths = npamps + elif model == 'w-tau-fixed-m-af': + truths = np.concatenate((npamps,[mf],[af])) + + if fitnoise: + truths = np.concatenate((truths,[1])) + + return truths + +def get_best_amps(pars,parser=None,nr_code=None): + nmax,model,samps_tr,half_points = pars + + + if model=='w-tau-fixed': + rg = (nmax+1) + elif model=='w-tau-fixed': + rg = (nmax+1)+2 + else: + rg = (nmax+1)*2 + + + if model=='w-tau-fixed-a-mf': + npamps = np.empty((nmax+1)) + for i in range(0,(nmax+1)): + amps_aux = samps_tr[i+rg][half_points:-1] + npamps[i] = np.quantile(amps_aux, 0.5) + else : + npamps = np.empty((nmax+1)*2) + for i in range(0,(nmax+1)*2): + amps_aux = samps_tr[i][half_points:-1] + npamps[i] = np.quantile(amps_aux, 0.5) + + if nr_code == 'Mock-data': + nm_mock = parser.get('rd-mock-parameters','nm_mock') + nm_mock = np.int(nm_mock) + amp_mock=np.empty(nm_mock+1) + ph_mock=np.empty(nm_mock+1) + for i in range(nm_mock+1): + amp_mockp = parser.get('rd-mock-parameters','amp'+str(i)) + amp_mock[i] = np.float(amp_mockp) + ph_mockp=parser.get('rd-mock-parameters','phase'+str(i)) + ph_mock[i] = np.float(ph_mockp) + + npamps = np.concatenate((amp_mock,ph_mock)) + return npamps + +def convert_m_af_2_w_tau_post(res,fitnoise=False): + + samples_2=res.samples + samps=f2.results.samples + + if fitnoise: + fmass_spin=(samps.T)[-3:-1].T + else: + fmass_spin=(samps.T)[-2:].T + #fmass_spin=new_samples[-2:] + fmass_spin_dist=[None]*len(fmass_spin) + weight=np.exp(res.logwt - res.logz[-1]) + for i in range(len(fmass_spin)): + fmass_spin_dist[i]=np.concatenate(dict_omega[qnm_model](fmass_spin[i,0],fmass_spin[i,1],2,2)) + + fmass_spin_dist_v2=np.asarray(fmass_spin_dist) + new_samples = dyfunc.resample_equal(fmass_spin_dist_v2, weight) + + return new_samples + +def save_object(obj, filename): + with open(filename, 'wb') as output: # Overwrites any existing file. + pickle.dump(obj, output, pickle.HIGHEST_PROTOCOL) + +def rm_files(files): + """ rm all old files """ + for i in files: + if os.path.exists(i): + os.remove(i) + \ No newline at end of file diff --git a/code_new/RD_Dynesty_Fits/RD_Dynesty_Fits/read_data.py b/code_new/RD_Dynesty_Fits/RD_Dynesty_Fits/read_data.py new file mode 100644 index 0000000000000000000000000000000000000000..87185de6364a1b89cb9223329e31dc5bb3e58391 --- /dev/null +++ b/code_new/RD_Dynesty_Fits/RD_Dynesty_Fits/read_data.py @@ -0,0 +1,344 @@ +# Copyright (C) 2021 Xisco Jimenez Forteza +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + +# +# ============================================================================= +# +# Preamble +# +# ============================================================================= +# +# Module to run PE on RD data +import numpy as np +import rdown_utilities as rd_ut +import romspline +import rdown as rd +import h5py +import json +from scipy import interpolate +from scipy.interpolate import interp1d + + +def read_data(nr_code,sim_path,mf=1,af=0,parser=None,RD=True,tshift=0,tend = 100,metadata_file=None): + if nr_code=='SXS': + gw = {} + gw = h5py.File(sim_path, 'r') + gw_data = gw["Extrapolated_N3.dir"]["Y_l2_m2.dat"] + times = gw_data[:,0] + + metadata = {} + with open(metadata_file) as file: + metadata = json.load(file) + + af = metadata['remnant_dimensionless_spin'][-1] + mf = metadata['remnant_mass'] + + tmax=rd_ut.FindTmaximum(gw_data[round(len(gw_data)/2):]) + times = times - tmax + + if RD: + position = np.argmax(times >= 0) + gw_data = gw_data[:,1][position:]+1j*gw_data[:,2][position:] + times = times[times >= 0] + + elif nr_code=='Maya': + dt=0.1 + gw = {} + gw = h5py.File(sim_path, 'r') + gw_sxs_bbh_0305_amp = np.asarray(gw['amp_l2_m2/Y'])[6:] + times_1 = np.asarray(gw['amp_l2_m2/X'])[6:] + gw_sxs_bbh_0305_amp_int = romspline.ReducedOrderSpline(times_1, gw_sxs_bbh_0305_amp) + gw_sxs_bbh_0305_pha = np.asarray(gw['phase_l2_m2/Y'])[6:] + times = np.asarray(gw['phase_l2_m2/X'])[6:] + gw_sxs_bbh_0305_pha_int = romspline.ReducedOrderSpline(times, gw_sxs_bbh_0305_pha) + + tmin=max(times_1[0],times[0]) + tmax=min(times_1[-1],times[-1]) + times=np.arange(tmin,tmax,dt) + amps=gw_sxs_bbh_0305_amp_int(times) + phs=gw_sxs_bbh_0305_pha_int(times) + gw_sxs_bbh_0305 = np.asarray([times,amps*np.cos(phs),amps*np.sin(phs)]).T + gw5_sxs_bbh_0305 = gw_sxs_bbh_0305 + + times = gw_sxs_bbh_0305[:,0] + tmax=rd_ut.FindTmaximum(gw_sxs_bbh_0305[round(len(gw_sxs_bbh_0305)/2):]) + times = times - tmax + + #times 6--> x axis of your data + times5 = gw5_sxs_bbh_0305[:,0] + tmax5=rd_ut.FindTmaximum(gw5_sxs_bbh_0305[round(len(gw_sxs_bbh_0305)/2):]) + times5 = times5 - tmax5 + #Select the data from 0 onwards + position = np.argmax( times >= (t_align)) + position5 = np.argmax(times5 >= (t_align)) + gw_sxs_bbh_0305rd=gw_sxs_bbh_0305[position+1:] + gw_sxs_bbh_0305rd5=gw5_sxs_bbh_0305[position5+1:] + timesrd=gw_sxs_bbh_0305[position:-1][:,0][:] + timesrd5=gw5_sxs_bbh_0305[position5:-1][:,0][:] + + elif nr_code=='LaZeV': + dt=0.1 + gw = {} + gw = h5py.File(simulation_path_1, 'r') + gw_sxs_bbh_0305_amp = np.asarray(gw['amp_l2_m2/Y'])[6:] + times_1 = np.asarray(gw['amp_l2_m2/X'])[6:] + gw_sxs_bbh_0305_amp_int = romspline.ReducedOrderSpline(times_1, gw_sxs_bbh_0305_amp) + gw_sxs_bbh_0305_pha = np.asarray(gw['phase_l2_m2/Y'])[6:] + times = np.asarray(gw['phase_l2_m2/X'])[6:] + gw_sxs_bbh_0305_pha_int = romspline.ReducedOrderSpline(times, gw_sxs_bbh_0305_pha) + + tmin=max(times_1[0],times[0]) + tmax=min(times_1[-1],times[-1]) + times=np.arange(tmin,tmax,dt) + amps=gw_sxs_bbh_0305_amp_int(times) + phs=gw_sxs_bbh_0305_pha_int(times) + gw_sxs_bbh_0305 = np.asarray([times,amps*np.cos(phs),amps*np.sin(phs)]).T + gw5_sxs_bbh_0305 = gw_sxs_bbh_0305 + + times = gw_sxs_bbh_0305[:,0] + tmax=rd_ut.FindTmaximum(gw_sxs_bbh_0305[round(len(gw_sxs_bbh_0305)/2):]) + times = times - tmax + + #times 6--> x axis of your data + times5 = gw5_sxs_bbh_0305[:,0] + tmax5=rd_ut.FindTmaximum(gw5_sxs_bbh_0305[round(len(gw_sxs_bbh_0305)/2):]) + times5 = times5 - tmax5 + + #Select the data from 0 onwards + position = np.argmax( times >= (t_align)) + position5 = np.argmax(times5 >= (t_align)) + gw_sxs_bbh_0305rd=gw_sxs_bbh_0305[position+1:] + gw_sxs_bbh_0305rd5=gw5_sxs_bbh_0305[position5+1:] + timesrd=gw_sxs_bbh_0305[position:-1][:,0][:] + timesrd5=gw5_sxs_bbh_0305[position5:-1][:,0][:] + + elif nr_code=='Mock-data': + times = np.arange(tshift,tend+10,0.1) + + nm_mock = parser.get('rd-mock-parameters','nm_mock') + nm_mock = np.int(nm_mock) + mf = parser.get('rd-mock-parameters','mf') + mf = np.float(mf) + af = np.float(parser.get('rd-mock-parameters','af')) + af = np.float(af) + + rdown=rd.Ringdown_Spectrum(mf,af,2,2,n=nm_mock,s=-2,time=times) + + w_mock=np.empty(nm_mock+1) + tau_mock=np.empty(nm_mock+1) + amp_mock=np.empty(nm_mock+1) + ph_mock=np.empty(nm_mock+1) + + for i in range(nm_mock+1): + wp_mock = parser.get('rd-mock-parameters','w'+str(i)) + w_mock[i] = np.float(wp_mock) + tp_mock=parser.get('rd-mock-parameters','tau'+str(i)) + tau_mock[i] = np.float(tp_mock) + amp_mockp = parser.get('rd-mock-parameters','amp'+str(i)) + amp_mock[i] = np.float(amp_mockp) + ph_mockp=parser.get('rd-mock-parameters','phase'+str(i)) + ph_mock[i] = np.float(ph_mockp) + + + pars = np.concatenate((w_mock,tau_mock,amp_mock,ph_mock)) + gw_data=rdown.rd_model_wtau(pars) + + return np.stack((times,gw_data)).T + +def nr_resize(data_1,data_2,tshift=0,tend=100): + times_1 = data_1[:,0].real + times_2 = data_2[:,0].real + data_1_re = data_1[:,1].real + data_1_im = data_1[:,1].imag + data_2_re = data_2[:,1].real + data_2_im = data_2[:,1].imag + + gwnew_re = interpolate.interp1d(times_1, data_1_re, kind = 'cubic') + gwnew_im = interpolate.interp1d(times_1, data_1_im, kind = 'cubic') + gwnew_re5 = interpolate.interp1d(times_2, data_2_re, kind = 'cubic') + gwnew_im5 = interpolate.interp1d(times_2, data_2_im, kind = 'cubic') + + if times_2[-1]>= times_1[-1]: + times_rd = times_1 + else: + times_rd = times_2 + + gwdatanew_re = gwnew_re(times_rd) + gwdatanew_im = gwnew_im(times_rd) + gwdatanew_re5 = gwnew_re5(times_rd) + gwdatanew_im5 = gwnew_im5(times_rd) + gwdatanew = gwdatanew_re + 1j*gwdatanew_im + gwdatanew5 = gwdatanew_re5 + 1j*gwdatanew_im5 + + position_in = np.argmax(times_rd >= tshift) + position_end = np.argmax(times_rd >= tend) + times_rd = times_rd[position_in:position_end] + gwdatanew = gwdatanew[position_in:position_end] + gwdatanew5 = gwdatanew5[position_in:position_end] + + return(np.stack((times_rd,gwdatanew)).T,np.stack((times_rd,gwdatanew5)).T) + + +def phase_align(data_1,data_2,t_align=0): + + #timesrd_final = data_1[:,0] + #phas = np.angle(data_1[:,1]) + #phas = np.unwrap(phas) + #phas5 = np.angle(data_2[:,1]) + #phas5 = np.unwrap(phas5) + #position = np.argmax(timesrd_final >= (t_align)) + #dphase = phas5[position]-phas[position] + + #gwdatanew = data_1[:,1]*np.exp(1j*dphase) + + + phas = np.angle(data_1[:,1]) + phas = np.unwrap(phas) + phas5 = np.angle(data_2[:,1]) + phas5 = np.unwrap(phas5) + position = np.argmax(data_1[:,0] >= (0)) + dphase = phas5[position]-phas[position] + gwdatanew = data_1[:,1]*np.exp(1j*dphase) + timesrd_final = data_1[:,0] + + return np.stack((timesrd_final,gwdatanew)).T + +def create_output_files(output_folder,pars,file_type): + sim_num, model, nmax, tshift, npoints = pars + + """ + Generate the output files you want to export the data to. + file_type must be one of this options: [corner_plot,corner_plot_extra,diagnosis,fit,post_samples,sampler_results,log_z] + """ + + if file_type=='corner_plot': + outfile = output_folder+'/Dynesty_'+str(sim_num)+'_'+model+'_nmax_'+str(nmax)+'_tshift_'+str(tshift)+'_'+str(npoints)+'corner_plot.png' + elif file_type=='corner_plot_extra': + outfile = output_folder+'/Dynesty_'+str(sim_num)+'_'+model+'_nmax_'+str(nmax)+'_tshift_'+str(tshift)+'_'+str(npoints)+'corner_plot_extra.png' + elif file_type=='diagnosis': + outfile = output_folder+'/Dynesty_diagnosis'+str(sim_num)+'_'+model+'_nmax_'+str(nmax)+'_tshift_'+str(tshift)+'_'+str(npoints)+'.png' + elif file_type=='fit': + outfile = output_folder+'/Fit_results_'+str(sim_num)+'tshift_'+str(tshift)+'_'+model+'_nmax_'+str(nmax)+'.png' + elif file_type=='post_samples': + outfile = output_folder+'/posterior_samples-'+str(sim_num)+'tshift_'+str(tshift)+'_'+model+'_nmax_'+str(nmax)+'.csv' + elif file_type=='sampler_results': + outfile = output_folder+'/results_'+str(sim_num)+'tshift_'+str(tshift)+'_'+model+'_nmax_'+str(nmax)+'.pkl' + elif file_type=='log_z': + outfile = output_folder+'/summary'+str(sim_num)+'_'+model+'_nmax_'+str(nmax)+'.csv' + elif file_type=='best_vals': + outfile = output_folder+'/best_values_'+str(sim_num)+'_'+model+'_nmax_'+str(nmax)+'.csv' + else: + print ('Something went wrong') + return + + return outfile + +def read_config_file(parser): + # Setup path and output folders + rootpath=parser.get('nr-paths','rootpath') + simulation_path_1 = parser.get('nr-paths','simulation_path_1') + + if parser.get('nr-paths','simulation_path_2'): + simulation_path_2 = parser.get('nr-paths','simulation_path_2') + else: + simulation_path_2 = simulation_path_1 + + metadata_file = parser.get('nr-paths','metadata_json') + simulation_number = parser.get('nr-paths','simulation_number') + simulation_number = np.int(simulation_number) + + output_folder = parser.get('output-folder','output-folder') + if parser.has_option('setup','export'): + export=eval(parser.get('setup','export')) + else: + export=True + + # Setup sampler and output options + overwrite = eval(parser.get('setup','overwrite')) + downfactor = np.int(parser.get('setup','plot_down_factor')) + sampler = parser.get('setup','sampler') + nr_code = parser.get('setup','nr_code') + if parser.has_option('setup','nb_cores'): + nbcores = np.int(parser.get('setup','nb_cores')) + else: + nbcores = 1 + + # time shift , end and align options + tshift=parser.get('time-setup','tshift') + tshift = np.float(tshift) + + tend=parser.get('time-setup','tend') + tend = np.float(tend) + + t_align=parser.get('time-setup','t_align') + t_align = np.float(t_align) + + # n-tones & nlive points + nmax=parser.get('n-tones','nmax') + nmax = np.int(nmax) + + npoints=parser.get('n-live-points','npoints') + npoints = np.int(npoints) + + # setup the RD model + model=parser.get('rd-model','model') + error_str = eval(parser.get('rd-model','error_str')) + fitnoise=eval(parser.get('rd-model','fit_noise')) + if fitnoise: + l_int=1 + index_mass=-3 + index_spin=-2 + # prior_dim = len(priors_min) + else: + index_mass=-2 + index_spin=-1 + l_int=0 + + if error_str: + error_val=np.float(parser.get('rd-model','error_val')) + if error_val==0: + error_type='' + else: + error_type=error_val + else: + error_type='False' + error_val =0 + + if nr_code == 'SXS': + metadata = {} + with open(metadata_file) as file: + metadata = json.load(file) + af = metadata['remnant_dimensionless_spin'][-1] + mf = metadata['remnant_mass'] + else: + mf = parser.get('rd-mock-parameters','mf') + mf = np.float(mf) + af = np.float(parser.get('rd-mock-parameters','af')) + af = np.float(af) + + if model == 'w-q': + tau_var_str='q' + else: + tau_var_str='tau' + + if nr_code == 'Mock-data': + nm_mock = int(parser.get('rd-mock-parameters','nm_mock')) + else: + nm_mock = None + + res = simulation_path_1,simulation_path_2, metadata_file , simulation_number, output_folder, export, overwrite, sampler,nr_code, nbcores,tshift,tend,t_align, nmax , npoints, model, error_str, fitnoise, l_int, index_mass,index_spin, error_type, error_val, af, mf,tau_var_str,nm_mock + return res \ No newline at end of file diff --git a/code_new/RD_Dynesty_Fits/RD_Dynesty_Fits/test/__init__.py b/code_new/RD_Dynesty_Fits/RD_Dynesty_Fits/test/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..8b137891791fe96927ad78e64b0aad7bded08bdc --- /dev/null +++ b/code_new/RD_Dynesty_Fits/RD_Dynesty_Fits/test/__init__.py @@ -0,0 +1 @@ + diff --git a/code_new/RD_Dynesty_Fits/RD_Fits.ipynb b/code_new/RD_Dynesty_Fits/RD_Fits.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..7b061a2315e2fe9ee07547ce47c5af7d06027171 --- /dev/null +++ b/code_new/RD_Dynesty_Fits/RD_Fits.ipynb @@ -0,0 +1,659 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 38, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'Generate ringdown templates in the time and perform parameter estimation on them.\\n'" + ] + }, + "execution_count": 38, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "\"\"\"Generate ringdown templates in the time and perform parameter estimation on them.\n", + "\"\"\"" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "#Import relevant modules, import data and all that\n", + "import time\n", + "import numpy as np\n", + "import corner\n", + "import matplotlib.pyplot as plt\n", + "from matplotlib.ticker import MaxNLocator\n", + "from matplotlib import rc\n", + "from configparser import ConfigParser\n", + "plt.rcParams.update({'font.size': 16.5})\n", + "\n", + "from multiprocessing import Pool\n", + "import random\n", + "import dynesty\n", + "from dynesty import plotting as dyplot\n", + "from dynesty.utils import resample_equal\n", + "from dynesty import utils as dyfunc\n", + "import os\n", + "import argparse\n", + "import scipy.optimize as optimization\n", + "from scipy.optimize import minimize\n", + "import rdown as rd\n", + "import rdown_pe as rd_pe\n", + "import rdown_utilities as rd_ut\n", + "import read_data as rdata" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "## Loading and running data tested with NR data\n", + "## Loading and running data tested with Mock data" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "usage: ipykernel_launcher.py [-h] [-c CONFIG_FILE]\n", + "ipykernel_launcher.py: error: unrecognized arguments: -f /work/francisco.jimenez/.local/share/jupyter/runtime/kernel-eb21fd9f-ea57-481c-b51d-230c5ef5a4a2.json\n" + ] + } + ], + "source": [ + "# Cell that calls the arguments from your 'config.ini' file. \n", + "try:\n", + " parser = argparse.ArgumentParser(description=\"Simple argument parser\")\n", + " parser.add_argument(\"-c\", action=\"store\", dest=\"config_file\")\n", + " result = parser.parse_args()\n", + " config_file=result.config_file\n", + " parser = ConfigParser()\n", + " parser.read(config_file)\n", + " parser.sections()\n", + "except SystemExit: \n", + " parser = ConfigParser()\n", + " parser.read('./run_0_mock/config_n0_to_1_mock.ini')\n", + " parser.sections()\n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "# Load variables from config file\n", + "(simulation_path_1,simulation_path_2, metadata_file , simulation_number, output_folder,\n", + " export, overwrite, sampler,nr_code, nbcores,tshift,tend,t_align,\n", + " nmax , npoints, model, error_str, fitnoise, l_int, index_mass,index_spin,\n", + "error_type, error_val, af, mf,tau_var_str,nm_mock)=rdata.read_config_file(parser)" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "model: w-tau\n", + "nmax: 0\n", + "nm_mock: 1\n", + "tshift: 0.2\n", + "error: True\n", + "error value: 0.002\n", + "export: True\n", + "nr code: Mock-data\n", + "fit noise: False\n" + ] + } + ], + "source": [ + "# Show configuration options\n", + "dim = nmax+1\n", + "ndim = 4*dim\n", + "numbins = 32 #corner plot parameter - how many bins you want\n", + " \n", + "print('model:',model)\n", + "print('nmax:',nmax)\n", + "print('nm_mock:',nm_mock)\n", + "print('tshift:',tshift)\n", + "print('error:', error_str)\n", + "print('error value:',error_val)\n", + "print('export:',export)\n", + "print('nr code:',nr_code)\n", + "print('fit noise:',fitnoise)" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "# Create output directories \n", + "if not os.path.exists(output_folder):\n", + " os.mkdir(output_folder)\n", + " print(\"Directory \" , output_folder , \" Created \")\n", + "\n", + "if nr_code == 'Mock-data': \n", + " nm_mock_str = 'rec_with'+parser.get('rd-mock-parameters','nm_mock')+'_'\n", + "else:\n", + " nm_mock_str=''\n", + " \n", + "if error_str:\n", + " output_folder_1=(output_folder+'/'+model+'-nmax'+str(nmax)+'_'+nm_mock_str+str(error_str)+'_'+str(error_type)+'_fitnoise_'+str(fitnoise))\n", + "else:\n", + " output_folder_1=output_folder+'/'+model+'-nmax'+str(nmax)+'_'+nm_mock_str+str(error_str)+'_'+'fitnoise_'+str(fitnoise)\n", + "\n", + "if not os.path.exists(output_folder_1):\n", + " os.mkdir(output_folder_1)\n", + " print(\"Directory \" , output_folder_1 , \" Created \")" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [], + "source": [ + "# Define output files \n", + "pars = [simulation_number,model,nmax,tshift,npoints]\n", + "corner_plot = rdata.create_output_files(output_folder_1,pars,'corner_plot')\n", + "corner_plot_extra = rdata.create_output_files(output_folder_1,pars,'corner_plot_extra')\n", + "diagnosis_plot = rdata.create_output_files(output_folder_1,pars,'diagnosis')\n", + "fit_plot = rdata.create_output_files(output_folder_1,pars,'fit')\n", + "samples_file = rdata.create_output_files(output_folder_1,pars,'post_samples')\n", + "results_file = rdata.create_output_files(output_folder_1,pars,'sampler_results')\n", + "sumary_data = rdata.create_output_files(output_folder_1,pars,'log_z')\n", + "best_data = rdata.create_output_files(output_folder_1,pars,'best_vals')\n", + "\n", + "files = [corner_plot,corner_plot_extra,diagnosis_plot,fit_plot,samples_file,results_file,sumary_data,best_data]" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [], + "source": [ + "# Remove old files if overwrite = True\n", + "if overwrite:\n", + " rd_ut.rm_files(files)" + ] + }, + { + "cell_type": "code", + "execution_count": 46, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/work/francisco.jimenez/venv/lib/python3.7/site-packages/numpy/core/_asarray.py:85: ComplexWarning: Casting complex values to real discards the imaginary part\n", + " return array(a, dtype, copy=False, order=order)\n", + "/work/francisco.jimenez/venv/lib/python3.7/site-packages/numpy/core/_asarray.py:85: ComplexWarning: Casting complex values to real discards the imaginary part\n", + " return array(a, dtype, copy=False, order=order)\n", + "/work/francisco.jimenez/venv/lib/python3.7/site-packages/numpy/core/_asarray.py:85: ComplexWarning: Casting complex values to real discards the imaginary part\n", + " return array(a, dtype, copy=False, order=order)\n", + "/work/francisco.jimenez/venv/lib/python3.7/site-packages/numpy/core/_asarray.py:85: ComplexWarning: Casting complex values to real discards the imaginary part\n", + " return array(a, dtype, copy=False, order=order)\n", + "/work/francisco.jimenez/venv/lib/python3.7/site-packages/ipykernel_launcher.py:19: RuntimeWarning: invalid value encountered in sqrt\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "error estimate: nan\n", + "mismatch: -2.220446049250313e-16\n", + "snr: nan\n" + ] + }, + { + "data": { + "image/png": "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Szi+rKwMe/bswYwZMxK2R+/39vaO+/XEz04DQDgcBgDceOONuO6665KeE72o8/bbb8cvf/lL3HnnnTjvvPOQl5cHIQS++MUvqo+TCQzbKRQ/s+13M2wTERFltXGUbWSburo6nH/++Sfc7/F4ACgXP1588cUnfbzq6mrU19fD7/fjgQcewPXXX4+qqqqEY8466yxs374dx48fT2g32NzcDAAoLi4ez0tJqri4GLm5uZBSnnT8L774Ir785S/j4YcfVrd5vV709fWlbDzjwTKSFEooI3GHRjmSiIiIaGKOHTuGvr6+US+OXLhwIYQQeOmll0bs8/v9I8orli5divr6emzbtg1tbW247777Rpx3zTXXAAD+4z/+Q90mpcSTTz6JnJwcnHvuuQBOrfXfiej1elx55ZX4zW9+g/3794/YHy0hiR47vEb8scceG9FdJd04s51CZodZvc0yEiIiItJStF67oaEBW7duHbH/5ptvRlFREW666SZs27YN/f39WLduHQKBAA4cOIAXX3wR27dvR15ennpOdXU1uru7sXnzZmzatGlEDTWgzGzfcMMNePDBB9HR0YEVK1bgv//7v/GnP/0J//Zv/6bWgEdb/335y1+e0DLuW7duxRtvvIGamhrccsstWLx4Mbq6uvDBBx/go48+UvtoX3bZZXjmmWeQl5eH6upq/PWvf8X27dtRVFQ07udOBYbtFDJYDBACkBIIBiTCwTB0Bv7xgIiIiFIv2onk5Zdfxssvv5ywT6fT4Y477gAAPProo6isrMSzzz6L119/HXa7HQsXLsTtt9+OxYsXJ5wXvUhycHAQ99577wmfe9u2bZg9ezaefvppPP3005g3bx7+/d//HbfeemsqXyIApUb8/fffx3e/+1288MILaG9vh9PpxPLly9Xe3wDwk5/8BHq9Hs899xy8Xi/OP/98bN++HevWrUv5mE6FONWWLJNFTU2N3LlzZ9qf93+2fgjvkPLniov/+TRYC60nOYOIiIi0tG/fPixZsiTTw6BJ7GTvISHEh1LKmmT7OO2aYiarXr3td3EVSSIiIqLpjGE7xbhkOxERERFFMWynWPzMNpdsJyIiIpreGLZTzGw3qrcZtomIiIimN4btFIsP2/4hhm0iIiKi6YxhO8USZrbZa5uIiIhoWmPYTjFTDsM2ERERESkYtlMsfsl2v4dLthMRERFNZwzbKRYftjmzTURERDS9MWynmMkeN7PtDWdwJERERESUaQzbKaY36WEwCgBAOCQRcLMjCREREdF0xbCtgYRVJAd8GRwJEREREWUSw7YG4leRZK9tIiIioumLYVsD8TPb3n7ObBMREZF2XnrpJQgh8Morr6Tl+d58800IIZJ+1dfXp2UMk4nh5IfQqUooI+GS7URERKSh2tpaAMDy5cvT+rx33nknzjrrrIRt5eXlaR3DZMCwrQFLbtzCNgzbREREpKHa2lrY7XbMmzcvrc+7evVqrF+/Pq3PORmxjEQDCUu2M2wTERGRhmpra7Fs2TIIIUY9bseOHVi3bh0cDgeKiopw1VVXoampSd2/du1aLFu2bMR5oVAIVVVVuPTSS0fsGxwcRDA4tnVF9uzZg1tuuQULFy6EzWZDeXk5Nm3ahO7u7oTjLrroIlx00UX4y1/+glWrVsFms6G6uhpvv/02AOCFF17AGWecgZycHKxcuRIHDx5MOP/SSy/F+eefj6eeegrLly+HxWLBggULsG3btjGNM9UYtjUQv7CNd5Bhm4iIiLThcrlw+PDhk5aQPPHEE1i7di1MJhMefPBB3HXXXXj33XdxySWXqGG5uroaBw8eRCiUuAL2s88+i4aGBtx///0J2zdu3AiHwwGr1YrPfOYzqKurG3UMTz75JJqamrBp0yY8+uijWL9+PZ555hnceuutCcfV1dWho6MDN9xwAz772c9iy5YtaGtrw3XXXYeHH34Y3/ve97Bx40Z84xvfwM6dO3HHHXeMOP/AgQP4xje+gauuugoPPfQQzGYzbrnlFrz33nujjlELLCPRQMIqkm4u2U5ERETaqKurg5QSp5122gmPqa2txW233YatW7fim9/8prp91apVWL16Nd566y2sWbMGS5cuhc/nw+HDh7FgwQIAQDAYxJYtW3DllVdixYoVAACTyYSrr74al1xyCZxOJ2pra/HQQw9h1apV+OCDD7Bo0aKk43jggQdgs9kStpnNZmzbtg1SSggh0Nraiu7ublgsFnz88ccoLi4GALjdbnznO9/Bb3/7W+zcuRMWiwUAcPDgQWzfvl19vP7+fjQ3N6OgoADvv/+++jquuOIKzJs3D88//zxWrlx5qj/mCWHY1oAlz6ze5pLtREREWer3v8/0CBJdfvkpnxKdTR5tZnvLli2YN28eNm3ahK6uLnX73LlzAQCNjY1Ys2YNqqurAQD19fVqSH366afR2NiY0Olk5cqVCYH185//PC6//HLU1NTgu9/9Lp577rmk44gP2r29vQiFQigsLITf7x/xeu6//341aANAXl4eAOCRRx5RgzYAOBwOmEyxSc7du3cDAO655x71NQBARUUFKisrE8pm0oVhWwNmR1zYdocgwxJCN3odFREREdGpOlknEp/Ph1dffRVutxslJSVJj3E4HACApUuXAlDC9mWXXYZAIID7778fGzZsGHXmHABOP/10XHzxxdixY0fS/cFgEE899RR++tOfYv/+/fB4POq+xYsXq/XmdXV1EELg8mEfPBoaGjBjxgycc845Cdv37duXMJMeDevXX3/9iDFIKZGTkzPq69ACw7YGdAYdjGYdAr4wpAT8Ln9CACciIiJKhdraWlRUVCA/Pz/p/sbGRrjdbnz/+9/H2WefnfSYmpoaAEBBQQFKS0vVXtm/+MUv0NTUhNdee21MY6moqDhh2L7uuuvwyiuv4MYbb8TXv/51OJ1OGI1G3HzzzQlBvra2FpWVlSgqKko4f9euXTjzzDNHXARaV1eHjRs3qvd3796NkpISlJaWJhzX09ODI0eOjKgPTweGbY2YbXoEfGEAypLtDNtERERZZhxlG9mmrq4O559//gn3R2eQq6urcfHFF5/08aqrq1FfXw+/348HHngA119/PaqqqsY0lsbGxoTSj6ja2lq88MILeOyxx3Dbbbep2w8dOoQjR47gK1/5SsLrSTZLX1tbi69+9asJ21paWtDT05Nw/O7du6HX64efjp///OeQUmakVSG7kWjEYo9b2GbQP8qRRERERKfu2LFj6OvrG7XEY+HChRBC4KWXXhqxz+/3o7+/P2Hb0qVLUV9fj23btqGtrQ333XffiPM6OztHbHvnnXfwxhtvYN26dSP2NTc3A0BCDbXP58NNN90EIFYCEwqFsG/fvhFh+8iRIxgYGBixPVoyEv/6d+/ejba2NjQ2NiY8/49+9CNs2LDhhBdvaokz2xrhKpJERESkpWi9dkNDA7Zu3Tpi/80334yioiLcdNNN2LZtG/r7+7Fu3ToEAgEcOHAAL774IrZv365efAgoM9vd3d3YvHkzNm3apF5EGW/Dhg2w2WxYuXIlnE4ndu/ejSeeeAJOpxObN28ecfyZZ54Jq9WK22+/HXfccQdcLheefvppmM3KX/2jIfrAgQPwer0jQvWuXbsSjouqq6uDTqdTa82jnUyWL1+Oz33uc/inf/onDAwM4PHHH4fD4cDjjz8+1h9tSjFsayR+YRvvAGe2iYiIKLWiM7svv/wyXn755YR9Op1O7T/96KOPorKyEs8++yxef/112O12LFy4ELfffjsWL16ccF40uA4ODuLee+9N+rzr16/Hc889h4cffhgDAwMoKSnBtddei82bN2P27Nkjji8rK8Pzzz+Pu+++G3fffTeWLFmC++67Dzt37sThw4cxZ86chNczPFTX1tbCZDKNGGtdXR3mz5+vdjmJdiL55S9/icceewz33HMP9Ho9LrvsMvzwhz8cUQeeLkJKqd2DC1EG4A4A5wCoAWAHcJGU8s0xnPsUgC8n2fV3KeW5Jzu/pqZG7ty585TGm0qH/nwUe99oBwDMqynE0isWnOQMIiIi0sK+ffuwZMmSTA+DNPbjH/8Y3/rWtzA0NASj0XjyE07Byd5DQogPpZQ1yfZpPbNdBeBbAA4CqAVwql3E3QCGXzY6slAoCyUsbMMyEiIiIiJN1dXVYcGCBSkP2hOlddj+EIBTStkthFgP4JWTHD9cQEr5bOqHpb2EMhIXF7YhIiIi0tLu3buz8i8YmnYjkVIOSim7J/IYQgi9ECI3VWNKF64iSURERJQeUkrs3bs3K8N2tl8gmQtgAIBNCNEN4FcA7pFSejM7rJMbvookEREREWlDCAGXy5XpYSSVzWG7FcC/AfgYgB7A5QD+GcASAJdkcFxjYrQZIQQgJRDwhRHyh6A3jWyyTkRERERTV9aGbSnlt4dt+k8hRDOAu4UQa6WU/zP8HCHELQBuAZC09Uw6CZ2A2aaHd0iZ1fYN+GBz2jI6JiIiIiJKr8m2guTDke+fTrZTSvmElLJGSlmTbLnQdOMqkkRERETT26QK21LKdgB+AIWZHstYJKwiybBNRERENO1MqrAthJgFwIRJ0mvbkstVJImIiIims6wI20KI+UKI+XH3LSdo9/evke9/Ss/IJoZhm4iIiGh60/wCSSHEvZGb0caHG4UQqwD0SSkfj2zbEfk+J/K9FMDHQohfA6iH8qHgcii12r+RUr6l9bhTweKIrSLpHeQqkkRERETTTTq6kWwZdv9/R74fBfA4kusD8AcAnwFwI5Sw3QDgLgA/SfkINcKwTURERDS9aR62pZRiDMfMGXa/D8BGjYaUNvGrSHLJdiIiIqLpJytqtqcqS75Fvc2wTURERDT9MGxryGgzQqdXJvajq0gSERERUeb19PRACIH/+3//r6bPw7CtoegqklHePm8GR0NERERT0UsvvQQhBF555ZW0PN+bb74JIUTSr/r6+rSMIRXq6uoAAKeddpqmz5O1y7VPFRa7AZ5BpYTE2+9DTklOhkdEREREU0ltbS0AYPny5Wl93jvvvBNnnXVWwrby8vK0jmEiomF72bJlmj4Pw7bG4pds9/b7MjgSIiIimopqa2tht9sxb968tD7v6tWrsX79es2fx+fzwWw2n/zAU7R7927MmjUL+fn5KX/seCwj0RgXtiEiIiIt1dbWYtmyZRBi9AZwO3bswLp16+BwOFBUVISrrroKTU1N6v61a9cmneUNhUKoqqrCpZdeOmLf4OAggsGTN4EIBAKor69Ha2vrqMdddNFFWLNmDd544w2sWrUKFosF//qv/6ruP9lrAIA9e/bglltuwcKFC2Gz2VBeXo5Nmzahu7s74bi6ujrNZ7UBhm3Nsdc2ERERacXlcuHw4cMnLSF54oknsHbtWphMJjz44IO466678O677+KSSy5Rw3J1dTUOHjyIUCixocOzzz6LhoYG3H///QnbN27cCIfDAavVis985jNqWUYyx48fx5IlS/Dtb3971HHW1dWhpaUF11xzDVavXo1HHnkEn//858f8GgDgySefRFNTEzZt2oRHH30U69evxzPPPINbb7014bn27Nmjeb02wDISzTFsExERZaff/z7TI0h0+eWnfk5dXR2klKOGxtraWtx2223YunUrvvnNb6rbV61ahdWrV+Ott97CmjVrsHTpUvh8Phw+fBgLFiwAAASDQWzZsgVXXnklVqxYAQAwmUy4+uqrcckll8DpdKK2thYPPfQQVq1ahQ8++ACLFi069RcCoLW1Fd3d3QgGg9i5c6c6hlN5DQDwwAMPwGazJTy22WzGtm3bIKWEEALHjh1Df39/Wma2GbY1xrBNREREWonOJo82s71lyxbMmzcPmzZtQldXl7p97ty5AIDGxkasWbMG1dXVAID6+no16D799NNobGxM6HSycuVKrFy5Ur3/+c9/Hpdffjlqamrw3e9+F88999yIMcyZMwdSyjG9lu985zsJQftUXgOAhKDd29uLUCiEwsJC+P2xct7du3cD0L4TCcCwrTmuIklERERaOVknEp/Ph1dffRVutxslJSVJj3E4HACApUuXAlDC9mWXXYZAIID7778fGzZsOGkoPf3003HxxRdjx44d430patj+whe+MO7XEAwG8dRTT+GnP/0p9u/fD4/Hox6zePFita69rq4Oer0eS5YsGfd4x4phW2MJq0gOcVEbIiKibDGeso1sU1tbi4qKihN21GhsbITb7cb3v/99nH322UmPqampAQAUFBSgtLRU7ZX9i1/8Ak1NTXjttdfGNJaKiooJhe3a2lrMmTMHs2bNGvdruO666/DKK6/gxhtvxNe//nU4nU4YjUbcfPPNCR8Y6urqsGDBAlgslqSPl0oM2xozWAwwGAWCAYlwSCLgDsBoM578RCIiIqKTqKurw/nnn3/C/dGZ3erqalx88cUnfbzq6mrU19fD7/fjgQcewPXXX4+qqqoxjaWxsRHFxcVjG3gSdXV1SWfox/oaamtr8cILL+Cxxx7Dbbfdpm4/dOgQjhw5gq985Svqtt27d6elhARgN5K0iO+17enxjHIkERER0dgcO3YMfX19o4bGhQsXQgiBl156acQ+v9+P/v7+hG1Lly5FfX09tm3bhra2Ntx3330jzuvs7Byx7Z133sEbb7yBdevWJR3HyVr/hUIh7Nu3L2nYHutraG5uBoCEem+fz4ebbroJQKzUJhgMor6+Pi0XRwKc2U4Li90AV69ycaRvkL22iYiIaOKi9doNDQ3YunXriP0333wzioqKcNNNN2Hbtm3o7+/HunXrEAgEcODAAbz44ovYvn078vLy1HOqq6vR3d2NzZs3Y9OmTeoFiPE2bNgAm82GlStXwul0Yvfu3XjiiSfgdDqxefPmpGONtv778pe/jKeeemrE/gMHDsDr9SYN27m5uWN6DWeeeSasVituv/123HHHHXC5XHj66afVBXGij33gwAH4fL60zWwzbKeBsrCNMqPt6eMqkkRERDRx0QsKX375Zbz88ssJ+3Q6He644w4AwKOPPorKyko8++yzeP3112G327Fw4ULcfvvtWLx4ccJ50YskBwcHce+99yZ93vXr1+O5557Dww8/jIGBAZSUlODaa6/F5s2bMXv27Am9lhNd6DmW11BWVobnn38ed999N+6++24sWbIE9913H3bu3InDhw9jzpw5Cc+VrpltcbI2LJNVTU2N3LlzZ6aHAQDY94dDOPh3ZdWiRSudqLokvcupEhERTWf79u1LS9cJmrpO9h4SQnwopaxJto8122lgzY9r/8de20RERETTBsN2GsSHbc8AwzYRERHRdMGwnQYM20RERETTE8N2GiQsbMNVJImIiIimDYbtNDDZTdAblOVBgwFlYRsiIiIimvoYttOEC9sQERERTT8M22lizY2FbW8/e20TERERTQcM22lizTOpt7mwDREREdH0wLCdJlaHUb3t6eeS7URERETTAcN2miS0/2PYJiIiIpoWGLbTxOKIlZFwFUkiIiKi6YFhO02sBbFe255B9tomIiIimg4YttPEWmhVbzNsExEREU0PDNtpYrAYYDAqC9uEQxJ+F+u2iYiIaOJeeuklCCHwyiuvpOX53nzzTQghkn7V19enZQyTieHkh1CqWB1GDHYrIdvT44HJbjrJGURERESjq62tBQAsX748rc9755134qyzzkrYVl5entYxTAYM22lkzTXEwnafD3mzMzwgIiIimvRqa2tht9sxb968tD7v6tWrsX79+rQ+52TEMpI04sI2RERElGq1tbVYtmwZhBCjHrdjxw6sW7cODocDRUVFuOqqq9DU1KTuX7t2LZYtWzbivFAohKqqKlx66aUj9g0ODiIYHNu1aHv27MEtt9yChQsXwmazoby8HJs2bUJ3d3fCcRdddBEuuugi/OUvf8GqVatgs9lQXV2Nt99+GwDwwgsv4IwzzkBOTg5WrlyJgwcPJpx/6aWX4vzzz8dTTz2F5cuXw2KxYMGCBdi2bduYxplqDNtpxLBNREREqeRyuXD48OGTlpA88cQTWLt2LUwmEx588EHcddddePfdd3HJJZeoYbm6uhoHDx5EKBRKOPfZZ59FQ0MD7r///oTtGzduhMPhgNVqxWc+8xnU1dWNOoYnn3wSTU1N2LRpEx599FGsX78ezzzzDG699daE4+rq6tDR0YEbbrgBn/3sZ7Flyxa0tbXhuuuuw8MPP4zvfe972LhxI77xjW9g586duOOOO0acf+DAAXzjG9/AVVddhYceeghmsxm33HIL3nvvvVHHqAWWkaSRrSC2sI27jxdIEhER0cTU1dVBSonTTjvthMfU1tbitttuw9atW/HNb35T3b5q1SqsXr0ab731FtasWYOlS5fC5/Ph8OHDWLBgAQAgGAxiy5YtuPLKK7Fi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\n", + "text/plain": [ + "<Figure size 864x576 with 1 Axes>" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "#Load NR data, align in time and resize. Plot real part and amplitude. Finally compute the mismatch and the snr estimate\n", + "data = rdata.read_data(nr_code,simulation_path_1,RD=True,tshift=tshift,tend = tend,metadata_file=metadata_file,parser=parser)\n", + "data_l = rdata.read_data(nr_code,simulation_path_2,RD=True,tshift=tshift,tend = tend,metadata_file=metadata_file,parser=parser)\n", + "data_r, data_lr = rdata.nr_resize(data,data_l,tshift=tshift,tend=tend)\n", + "times_rd = data_r[:,0]\n", + "\n", + "plt.figure(figsize = (12, 8))\n", + "plt.plot(times_rd, data_r[:,1].real, \"r\", alpha=0.3, lw=3, label=r'$Lev6$: real')\n", + "plt.plot(times_rd, np.sqrt((data_r[:,1].real)**2+(data_r[:,1].imag)**2), \"r\", alpha=0.3, lw=3, label=r'$Lev5\\,amp$')\n", + "plt.plot(times_rd, data_lr[:,1].real, \"b\", alpha=0.3, lw=3, label=r'$Lev5: real$')\n", + "plt.plot(times_rd, np.sqrt((data_lr[:,1].real)**2+(data_lr[:,1].imag)**2), \"b\", alpha=0.3, lw=3, label=r'$Lev5\\,amp$')\n", + "if error_str and error_val==0:\n", + " error = np.sqrt(data_r[:,1]*data_r[:,1]-2*data_r[:,1]*data_lr[:,1]+data_lr[:,1]*data_lr[:,1])\n", + " error_est=np.sqrt(error.imag**2+error.real**2)\n", + " plt.plot(times_rd, error_est, \"g\", alpha=0.3, lw=2, label='error')\n", + "plt.legend()\n", + "\n", + "mismatch=1-rd_ut.EasyMatchT(times_rd,data_r[:,1],data_lr[:,1],tshift,tend)\n", + "error=np.sqrt(2*mismatch)\n", + "print('error estimate:',error)\n", + "print('mismatch:', mismatch)\n", + "print('snr:', rd_ut.EasySNRT(times_rd,data_r[:,1],data_lr[:,1],tshift,tend)/error**2)" + ] + }, + { + "cell_type": "code", + "execution_count": 47, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "error estimate: nan\n", + "mismatch: -2.220446049250313e-16\n", + "snr: nan\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/work/francisco.jimenez/venv/lib/python3.7/site-packages/ipykernel_launcher.py:13: RuntimeWarning: invalid value encountered in sqrt\n", + " del sys.path[0]\n" + ] + } + ], + "source": [ + "# Phase alignement\n", + "if parser.has_option('rd-model','phase_alignment'):\n", + " phase_alignment=eval(parser.get('rd-model','phase_alignment')) \n", + "else:\n", + " phase_alignment=False\n", + " \n", + "if phase_alignment:\n", + " datar_al = rdata.phase_align(data_r,data_lr)\n", + " gwdatanew5 = data_lr[:,1]\n", + " gwdatanew = datar_al[:,1] \n", + " timesrd_final = datar_al[:,0]\n", + " mismatch=1-rd_ut.EasyMatchT(timesrd_final,gwdatanew,gwdatanew5,tshift,tend)\n", + " error=np.sqrt(2*mismatch)\n", + " print('error estimate:',error)\n", + " print('mismatch:', mismatch)\n", + " print('snr:', rd_ut.EasySNRT(timesrd_final,gwdatanew,gwdatanew5,tshift,tend)/error)\n", + " if error_str:\n", + " error = np.sqrt(gwdatanew*gwdatanew-2*gwdatanew*gwdatanew5+gwdatanew5*gwdatanew5)\n", + " error_est=np.sqrt(error.imag**2+error.real**2)\n", + " else :\n", + " error = 1 \n", + "else:\n", + " datar_al = data_r\n", + " timesrd_final = datar_al[:,0]\n", + " \n", + "#Test the new interpolated data\n", + "if error_str and error_val==0:\n", + " plt.figure(figsize = (12, 8))\n", + " plt.plot(timesrd_final, datar_al[:,1].real, \"r\", alpha=0.3, lw=2, label='Original')\n", + " plt.plot(timesrd_final, data_lr[:,1].real, \"b\", alpha=0.3, lw=2, label='Aligned')\n", + " plt.plot(timesrd_final, error_est, \"b\", alpha=0.3, lw=2, label='error')\n", + " plt.legend()" + ] + }, + { + "cell_type": "code", + "execution_count": 48, + "metadata": {}, + "outputs": [], + "source": [ + "# Define your noise depending on the noise configuration. Load priors and setup the likelihood with rd_pe.Ringdown_PE. \n", + "if error_str and error_val==0:\n", + " error_final = error_est\n", + " norm_factor = 100*len(error_final)/2*np.log(2*np.pi)\n", + "elif error_str and error_val!=0:\n", + " datar_al[:,1]+=random.uniform(0, error_val)\n", + " datar_al[:,1]+=1j*random.uniform(0, error_val)\n", + " error_tsh = error_val\n", + " error_final=(error_tsh.real**2+error_tsh.imag**2)\n", + " norm_factor = 0\n", + "else:\n", + " error_tsh=1\n", + " error_final=(error_tsh.real**2+error_tsh.imag**2)\n", + " norm_factor = 0\n", + "\n", + "priors = rd_pe.load_priors(model,parser,nmax,fitnoise=fitnoise)\n", + "rdown=rd.Ringdown_Spectrum(mf,af,2,2,n=nmax,s=-2,time=timesrd_final)\n", + "rdown_pe = rd_pe.Ringdown_PE(rdown,datar_al,dim,priors,errors2=error_final,norm_factor=norm_factor,model=model,l_int=l_int)" + ] + }, + { + "cell_type": "code", + "execution_count": 49, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "best fit pars from fit: [ 0.2 10.52057151 0.08836181 6.28318531]\n" + ] + } + ], + "source": [ + "# Get a first estimate by trying to fit the data.\n", + "nll = lambda *args: -rdown_pe.log_likelihood(*args)\n", + "if model == 'w-tau-fixed-m-af':\n", + " if fitnoise:\n", + " initial = np.concatenate((np.ones(2*dim),[0.8,0.9,1]))\n", + " soln = minimize(nll, initial,bounds=priors)\n", + " vars_ml=soln.x\n", + " else:\n", + " initial = np.concatenate((np.ones(2*dim),[0.8,0.9]))\n", + " soln = minimize(nll, initial,bounds=priors)\n", + " vars_ml=soln.x\n", + "elif model == 'w-tau-fixed':\n", + " if fitnoise:\n", + " initial = np.concatenate((np.ones(2*dim),[0.2]))\n", + " soln = minimize(nll, initial,bounds=priors)\n", + " vars_ml=soln.x\n", + " else:\n", + " initial = np.ones(2*dim)\n", + " soln = minimize(nll, initial,bounds=priors)\n", + " vars_ml=soln.x\n", + "else:\n", + " if fitnoise:\n", + " initial = np.concatenate((np.ones(ndim),[1]))\n", + " soln = minimize(nll, initial,bounds=priors)\n", + " vars_ml=soln.x\n", + " else: \n", + " initial = np.ones(ndim)\n", + " soln = minimize(nll, initial,bounds=priors)\n", + " vars_ml=soln.x\n", + "print(\"best fit pars from fit: \",vars_ml)" + ] + }, + { + "cell_type": "code", + "execution_count": 50, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "46474it [21:02, 36.81it/s, +1000 | bound: 286 | nc: 1 | ncall: 1106811 | eff(%): 4.289 | loglstar: -inf < -959286.172 < inf | logz: -959328.014 +/- 0.280 | dlogz: 0.000 > 0.010]" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "645.863601611\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\n" + ] + } + ], + "source": [ + "mypool = Pool(nbcores)\n", + "mypool.size = nbcores\n", + "\n", + "start = time.process_time()\n", + "f2=dynesty.NestedSampler(rdown_pe.log_likelihood,rdown_pe.prior_transform, len(priors), nlive=npoints,sample=sampler,pool=mypool)\n", + "if parser.has_option('setup','dlogz'):\n", + " dlogz=np.float(parser.get('setup','dlogz')) \n", + " f2.run_nested(dlogz=dlogz,print_progress=False)\n", + "else:\n", + " f2.run_nested(print_progress=False)\n", + "\n", + "print(time.process_time() - start)" + ] + }, + { + "cell_type": "code", + "execution_count": 52, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Summary\n", + "=======\n", + "nlive: 1000\n", + "niter: 46474\n", + "ncall: 1106811\n", + "eff(%): 4.289\n", + "logz: -959328.014 +/- 0.280\n" + ] + } + ], + "source": [ + "res = f2.results\n", + "res.samples_u.shape\n", + "res.summary()\n", + "samps=f2.results.samples\n", + "postsamps = rd_ut.posterior_samples(f2)\n", + "samps_tr=np.transpose(samps)\n", + "half_points=int(round((len(samps_tr[0])/1.25)))\n", + "evidence = res.logz[-1]\n", + "evidence_error = res.logzerr[-1]\n", + "if export:\n", + " rd_ut.save_object(res, results_file)" + ] + }, + { + "cell_type": "code", + "execution_count": 53, + "metadata": {}, + "outputs": [], + "source": [ + "pars = nmax,model,samps_tr, half_points\n", + "npamps = rd_ut.get_best_amps(pars,parser=parser,nr_code=nr_code)" + ] + }, + { + "cell_type": "code", + "execution_count": 54, + "metadata": {}, + "outputs": [], + "source": [ + "if export:\n", + " pars = simulation_number, nmax, tshift, evidence, evidence_error\n", + " rd_ut.export_logz_files(sumary_data,pars)" + ] + }, + { + "cell_type": "code", + "execution_count": 55, + "metadata": {}, + "outputs": [], + "source": [ + "labels = rd_ut.define_labels(dim,model,fitnoise)\n", + "if export:\n", + " pars = tshift, len(priors), labels \n", + " rd_ut.export_bestvals_files(best_data,postsamps,pars)" + ] + }, + { + "cell_type": "code", + "execution_count": 56, + "metadata": {}, + "outputs": [], + "source": [ + "w, tau = rdown.QNM_spectrum()\n", + "pars = w, tau, mf, af, npamps \n", + "truths = rd_ut.get_truths(model,pars,fitnoise)" + ] + }, + { + "cell_type": "code", + "execution_count": 57, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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97//fW666Sby8vLwer3G4//IyEij80BzczP//d//zYwZM/jiF79olAr861//4txzz+Xdd981Fl65XC4j6AwNDTVKDEwmk7FIq62tjauvvhqAzZs309jYSFRUFCEhIca5bTabEexaLBZiYmJ45JFHsFqtlJeXs2zZMmprawkNDeXYsWPs3LnTCKBSUlK4/PLLjS4EN954I3/605/4xje+QUVFBW63G4fDwY4dOygvL+fgwYPMmjWLBQsWsHv3bu68807MZjPvv/8+x44dIy0tjQULFjB37lycTifFxcVUV1fT1NSEyWTCZrNht9tJTU3tdltY6TQghBBCjB5jLngdK/zZu/j4eNxu90lZu8C611mzZmG322lvb2ft2rXk5eUxbdo0nE4n0dHRvP3227z11ltMnDiRtLQ08vLySExM5P333+eLX/wi3/jGN3qtw3z44Yd58sknAfjkk0944okniIqKwmKxDKhpfUREBPPnzycxMRGHw8F1113HBRdcwP/8z/+c9rgbbriBv/3tb/zoRz/i/PPP59lnn2Xr1q1897vfpaKigoyMjG6PO++88/je977Hk08+idPpZNq0aSQlJVFfX8+6deu4/vrreemll1BKcezYMTIzM4mKiqK4uJjW1lbS09PJzc2lqamJY8eOYbfbycvLIy0tjUmTJuFwOE7KtgohxGiglLoP+DqQCuwG7tdabznTYwZyXiFGEwleh0hISAjx8fEcO3aM8PBwrFYrJpMJrfVJda+JiYlYLBZCQkKoqamhs7OT6OhoZs6cyaRJk9i+fTu7du0iLS2NlStXcsUVV1BdXc369evZsmULHR0dRrY1cMtVl8tl9EL9+c9/zjXXXMPUqVP52c9+xt69e7nnnnuw2Wx8/PHHvPzyyxw+fJiGhgauuuoqPB4PmzdvZuHChWRnZwO+UgGbzQZgbB4A8NWvfpWWlhZWr17NNddcQ1xcHAB1dXXGdTmdTkJCQrj11lu5++67qaurw2q1EhcXR21tLeBrtZWSkkJLS4uxxeucOXOMjQnuv/9+8vPzueeee3C5XHz729/m+9//PgDf/e532bZtGzExMUa3ggsvvNAoBTjvvPPIyMjgwAFfmbQ/aAUoLi6moKDAKKXQWqO1prm52djC1/+Pj6HqNiCEODsppdYCT2mtn+rms5uAXwH3AJuBVcBqpdQUrXVND+fr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228TEBBAz549KSoqYsuWLRw8eJApU6YQFBTE2LFj8fPzY+DAgWzcuJFRo0Yd0/pKr9eTnJxMVlYW6enp9OnTB6vVisvlOkrkdK1wPxvRO7vdjsViITExkUGDBgFuCzB/f3/AXXjXo0cPSkpKABgyZAi9e/fm73//O+AWrBMmTABgxYoVuFwuioqK2LFjB6+88gpGo5Hbb7+d7777jt///vciLxYgKipKNKS46aabcLlcvPrqq1x//fXs2rWLX/3qV7z//vtERUXh7++Pt7c3e/bsYfPmzdxxxx0EBgZisVg4dOgQn3/+OU6nk/T0dGFv5hk53bFjB1u3bsVms+Hj40N8fDypqanMnTsXm81GXFwcffr0ISIiopNVltPppLW1FYvFIpp7dBWFnk4EyrWrnOeubWeVc6jT6aiqqupUzHUs1KKqs8/MmTOB8+eFej63d773TUXlcuVsidebcRdrlUuS1Ai0AP5AEFAApACRwChZlvedpW12QpKkQUAcEApkAXuO2HD9bAF7PE4UxdFoNDgcDg4dOkRTUxNpaWkALF26lIaGBq6//noCAwPp3r27iOr9+OOPVFdXU1lZidFoJC4uDr1ez/79+wG3hVZ7eztWq1XcnJU2oOAu/lF6y+v1egoLCwF3xX337t3Jy8sjPz+f0NBQHn74YYqKivD392fLli2Eh4ezZ88e2traRFSspaVFNDKoqanhq6++QpZlEhIS8PLywtvbW0RRt27dSnNzs2gAsG+f+zQ/8MADHDx4kGuuuUZEidvb23nvvfeE9Y3ZbBYi9YYbbmDTpk089NBDLF26VPjWKuPq0aMHy5YtIy8vj8rKStLT04XFUmhoKA6HA6fTyaZNm0hISODrr78WDgJXXHFFp1xWf39/jEYjO3fuZOfOnVgsFkaMGEF1dTUxMTGYTCYMBsNRXbXOZvTOZrOxZs0atFotu3fvpmfPnrS2tgqhpLRf9fLyws/Pj3feeYekpCRuv/12br755k7V9opwW716NZMmTWLSpEmsX78egB49etDR0dHJncLhcIjjIUkSISEhNDU1sWzZMp566imGDRvG/v37iYqKYuTIkQwcOJCnn36agoICXnrpJRYsWEBwcLCItlutVjQajbAni42NpaCggMrKShISEtixYwdZWVnYbDZGjhxJUlISgwcPZsWKFeTm5hIcHMzQoUMBOnXS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LTt37qSkpITOzk7CwsIYNWoUCxcupKmpiaeffpo1a9YwceJEteAlOzub7OxsysrK+M53vsO9997L3XffTUFBATabjaqqKu6//34SExO577770Ol0PPzww7hcLgwGg5qH1tjYqEZty8vLVfFXX1+vDmU7HA7+/e9/k5qail6vVwVJTU2N6td666238txzz6HT6fjWt76FEIL8/HwefvhhduzYAUB0dDQjRozgW9/6FkFBQRw6dIhZs2axePFi0tPT+fDDD9m1axdRUVHMnz+fFStWYDab8fPzw8vLC7PZzIwZM/jd735HdXU1VquVlStXsnPnThISEoiPj+9mEXU+UY5Ra2ur6pHb0tKiitaGhga+/PJLhBAYDAbS0tKIjIykqamJmTNn8vrrr1NbW4vVau0W0Zw7dy6+vr4EBwczfvx4PvzwQ/z8/JgxYwbf+c532Lx5M2lpaTQ1NdHe3q4Wh11xxRU0NjaSkJDAoUOH1DzR0aNH84c//EEtCjt27BipqakUFRWRkJBAbm4uHR0dtLa24uXlxYkTJ9RWviEhIXR2duLr60tKSgoWi6Xby53RaFRffHx9fdV5HA4HR44c4fDhw4wZM0adtzeU/HCbzYbL5UKv16tNFU4ldh0OBy6Xq1sebH9fWIaL68CFxsyZMy/a9Q31vmloXKqcF5/XrlQCTwErgBuFEG8AfwP+BHQAGwDb+dhGTwY6POhZBNSX2FVM2PPy8jCZTCQlJREUFMS1115LdnY2S5YsUYdhW1pa1IYHCxcupKCggIyMDHJzc9m8eTMrVqzA6XRy+eWX09TUxD333AO4rbtSUlIwmUzEx8fz4osvkpGRwR//+EfAnRdpsVj44IMP+L//+z8eeOABfvWrX3HttdcC7jy00NBQwC2olBzK6Oho1eRf8aWVUvLiiy/y3HPPYbFY+N///V9uvfVWhBDo9XoOHz6Mn58fzz33HGVlZfzoRz/is88+47vf/S533nknQghuuOEG4uPjufHGG9m8eTPLly9n27ZtTJgwgRUrVlBcXKymKMydO5frrruO2tpaNm3aRHh4OCaTiaamJkJDQzl69CgWi4URI0awbNky9uzZw6ZNm8jLy2PlypV9FkH1xmDmNppMJkaPHk10dLSawlFfX4+vry+7du3innvuOSm6mpqayurVq5k0aRJ//etf2bJlCytWrECn03H8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\n", + "text/plain": [ + "<Figure size 698.4x698.4 with 16 Axes>" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "fg=corner.corner(postsamps,quantiles=[0.05,0.5,0.95],show_titles=True,max_n_ticks = 4,bins=50,truths=truths,labels=labels,truth_color='red')\n", + "plt.show()\n", + "if export:\n", + " fg.savefig(corner_plot, format = 'png', bbox_inches = 'tight')" + ] + }, + { + "cell_type": "code", + "execution_count": 58, + "metadata": {}, + "outputs": [], + "source": [ + "from importlib import reload\n", + "reload(rd_ut)\n", + "if model == 'w-tau-fixed-m-af' and export == True: \n", + " truths=np.concatenate((w,tau))\n", + " labels_mf = np.concatenate((w_lab,tau_lab))\n", + " new_samples = rd_ut.convert_m_af_2_w_tau_post(res,fitnoise=False)\n", + " figure = corner.corner(new_samples,truths=truths,quantiles=[0.05,0.95],labels=labels_mf,smooth=True,color='b',truth_color='r',show_titles=True)\n", + " figure.savefig(corner_plot_extra, format = 'png', bbox_inches = 'tight')" + ] + }, + { + "cell_type": "code", + "execution_count": 151, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "<Figure size 1152x1152 with 4 Axes>" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "#lnz_truth = ndim * -np.log(2 * 10.) # analytic evidence solution\n", + "fig, axes = dyplot.runplot(res)\n", + "fig.tight_layout()\n", + "if export:\n", + " fig.savefig(diagnosis_plot, format = 'png', dpi = 384, bbox_inches = 'tight')" + ] + }, + { + "cell_type": "code", + "execution_count": 166, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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+tP83d/9HW9+85t56qmnVq1SkAb7nSiTkfsg0FQepZRSSi3Z+aTNrDcPPvggz372s5+2rF6XuVCf8Yxn8F3f9V3n3EZ3dzfveMc7eMc73sH999/Pddddxy233ML1119PqVSar+wD8N73vpdf+IVfYHJyksHBQQBuvvlmXvCCFzA7O/u07c7NzfEv//IvHDt2jEKhwNvf/nZ+67d+i1tvvZVXvepVF3roi9I0nk6VzUKrtdZ7oZRSSil10YRhyKOPPvodwf4VV1yBMYZbbrnlO57TarXmg/L2XP5ELpfDWsv27YuPZ7j99tsZGRmZD/QnJyf50Ic+xAc+8IHvWPfAgQP09fWxZcuW+WXXXHMNjzzyyNIPcpm027dTZbPg+2u9F0oppZRSF82BAwdoNBrfEex3d3fzEz/xE3zkIx9hdnaWV73qVfi+z4EDB/jUpz7FF7/4RXp7e3nPe97D448/zutf/3r27NnDiRMn+PCHP8xll13G2972tu94vZmZGd71rnfxm7/5m/PLfuVXfoWf+7mfo6+v7zvWr1ar82MDEj09PVQqlZU5AYvQYL8TRZGk8tRqa70nSimllFIXTTI4d2GwD/CHf/iH7N69m0984hN84QtfoKuriyuuuIKf+ZmfYd++fQC8+tWvZmJigptvvplyucyuXbt461vfyvvf//6nleEEaDQavPGNb+R1r3sdP/ZjPwbAvffey7e//W3+5E/+ZNH9K5VKzM3NPW1ZuVymq6vrgo/9TIy1dtU2vtnt37/f3nXXXRf3RX1fBucODsLp07Bt28V9faWUUkqte48++ihXX331Wu/GhhWGIW9+85vp6uri4x//OMYYAD70oQ/xq7/6q/PB++zsLJ7n8cM//MN8+MMfZm5ujsHBQY4dOzafynP11VfzoQ996Kw5++d6v4wxd1tr9y/2mObsd5pMRmrsz82B48ggXaWUUkoptWJ+8id/kkajwV/+5V/OB/oA73rXuzh48CD33Xcf9913H294wxv42Z/9WX7nd34HkHSi173udXzwgx+k0Wjw8Y9/nHK5zE033bRq+6ppPJ2oVILxcanE4/takUcppZRSaoUcOXKEv/zLvySfz9Pf3z+//LOf/SwveclLKBaL88sKhQJdXV30tpVD/7M/+zPe9ra3MTAwwN69e7nllltWrewmaLDfmRwnHaCrPftKKaWUUitm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\n", + "text/plain": [ + "<Figure size 864x648 with 1 Axes>" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "if export:\n", + " dict = {'w-tau':rdown.rd_model_wtau , 'w-q': rdown.rd_model_wq, 'w-tau-fixed':rdown.rd_model_wtau_fixed,'w-tau-fixed-m-af': rdown.rd_model_wtau_m_af}\n", + " figband = plt.figure(figsize = (12, 9))\n", + " plt.plot(datar_al[:,0].real,datar_al[:,1].real, \"green\", alpha=0.9, lw=3, label=r'$res_{240}$')\n", + " onesig_bounds = np.array([np.percentile(postsamps[:, i], [5, 95]) for i in range(len(postsamps[0]))]).T\n", + " samples_1sigma = filter(lambda sample: np.all(onesig_bounds[0] <= sample) and np.all(sample <= onesig_bounds[1]), postsamps)\n", + " samples_1sigma_down = list(samples_1sigma)[::downfactor]\n", + " for sample in samples_1sigma_down:\n", + " plt.plot(datar_al[:,0].real, dict[model](sample).real, \"r-\", alpha=0.1, lw=1)\n", + " plt.title(r'Comparison of the MC fit data and the $1-\\sigma$ error band')\n", + " plt.legend()\n", + " plt.xlabel('t')\n", + " plt.ylabel('h')\n", + " plt.show()\n", + " figband.savefig(fit_plot)" + ] + }, + { + "cell_type": "code", + "execution_count": 162, + "metadata": {}, + "outputs": [], + "source": [ + "if export:\n", + " with open(samples_file,'w') as file:\n", + " writer = csv.writer(file)\n", + " writer.writerow(labels)\n", + " writer.writerows(samps[::downfactor])" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.7" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/code_new/RD_Dynesty_Fits/README.md b/code_new/RD_Dynesty_Fits/README.md new file mode 100644 index 0000000000000000000000000000000000000000..7cc7b24cd05b42cde9b1308fa2bbd6de4f09c4dc --- /dev/null +++ b/code_new/RD_Dynesty_Fits/README.md @@ -0,0 +1,2 @@ +A package that fits RD waveforms with the dynesty sampler + diff --git a/code_new/RD_Dynesty_Fits/Run_Setup.ipynb b/code_new/RD_Dynesty_Fits/Run_Setup.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..1d8a77990e8b9c78cf92d0eb4f3ec626d285eb66 --- /dev/null +++ b/code_new/RD_Dynesty_Fits/Run_Setup.ipynb @@ -0,0 +1,167 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 4, + "id": "square-toddler", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "b''" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "\"\"\"\n", + "Created by Sumit Kumar on 2020-03-08 && modified by Xisco on 2021-04\n", + "Last modified:\n", + "\"\"\"\n", + "\n", + "import os, sys, numpy, glob, argparse\n", + "from datetime import date\n", + "import subprocess\n", + "from subprocess import call\n", + "import re\n", + "from configparser import ConfigParser\n", + "\n", + "today = date.today()\n", + "date = today.strftime(\"%Y%m%d\")\n", + "\n", + "runname='run_0_mock'\n", + "nmax = 0\n", + "config_file ='config_n0_to_1_mock.ini'\n", + "overwrite = True\n", + "\n", + "######\n", + "times = '(0 0.2 0.4 0.8 1.2 2 2.5 5 7.5 10 12 15 18 20)'\n", + "accounting_group = 'cbc.test.pe_ringdown'\n", + "cpus=8\n", + "nlive_points = 2000\n", + "req_memory=\"16GB\"\n", + "not_user='frjifo@aei.mpg.de'\n", + "pythonfile='/work/francisco.jimenez/sio/git/rdstackingproject/code_new/RD_Fits.py'\n", + "pythonscript='/work/francisco.jimenez/venv/bin/python'\n", + "#######################################################\n", + "\n", + "pwd = os.getcwd()\n", + "run_dir = '%s/%s'%(pwd,runname)\n", + "logs_dir = '%s/logs'%run_dir\n", + "\n", + "os.system('mkdir -p %s'%logs_dir)\n", + "os.system('cp %s %s/'%(config_file,run_dir))\n", + "\n", + "###########################################################################\n", + "# Creating Condor submit file\n", + "###########################################################################\n", + "filename1 = '%s/%s'%(run_dir,'condor_submit')\n", + "text_file1 = open(filename1 + \".sub\", \"w\")\n", + "text_file1.write(\"universe = vanilla\\n\")\n", + "text_file1.write(\"getenv = true\\n\")\n", + "text_file1.write(\"# run script -- make sure that condor has execute permission for this file (chmod a+x script.py)\\n\")\n", + "text_file1.write(\"executable = \"'%s/%s'%(run_dir,runname+'.sh \\n'))\n", + "text_file1.write(\"# file to dump stdout (this directory should exist)\\n\")\n", + "text_file1.write(\"output = %s/%s-$(Process).out\\n\"%(logs_dir,runname))\n", + "text_file1.write(\"# file to dump stderr\\n\")\n", + "text_file1.write(\"error = %s/%s-$(Process).err\\n\"%(logs_dir,runname))\n", + "text_file1.write(\"# condor logs\\n\")\n", + "text_file1.write(\"log = %s/%s-$(Process).log\\n\"%(logs_dir,runname))\n", + "text_file1.write(\"initialdir = %s \\n\"%run_dir)\n", + "text_file1.write(\"notify_user =\"+not_user+' \\n')\n", + "text_file1.write(\"notification = Complete\\n\")\n", + "text_file1.write('''arguments = \"-processid $(Process)\" \\n''')\n", + "text_file1.write(\"request_memory = \"+str(req_memory)+\"\\n\")\n", + "text_file1.write(\"request_cpus = \"+str(cpus)+\"\\n\") \n", + "text_file1.write(\"on_exit_remove = (ExitBySignal == False) || ((ExitBySignal == True) && (ExitSignal != 11))\\n\")\n", + "text_file1.write(\"accounting_group = %s\\n\"%accounting_group)\n", + "text_file1.write(\"queue 1\\n\")\n", + "text_file1.write(\"\\n\")\n", + "text_file1.close()\n", + "\n", + "###########################################################\n", + "# Creating python executable file\n", + "############################################################\n", + "filename2 = run_dir+'/'+runname+'.sh'\n", + "text_file2 = open(filename2, \"w\") \n", + "text_file2.write(\"#! /bin/bash \\n\")\n", + "text_file2.write(\"\\n\")\n", + "text_file2.write(\"times=\"+times+\"\\n\")\n", + "text_file2.write(\"config_file=\"+config_file+\"\\n\")\n", + "text_file2.write(\"pythonfile=\"+pythonfile+\"\\n\")\n", + "text_file2.write(\"pythonscript=\"+pythonscript+\"\\n\")\n", + "text_file2.write(\"\\n\")\n", + "text_file2.write(\"for i in ${times[@]}; do\\n\")\n", + "text_file2.write(\" awk -v a=\\\"$i\\\" '/^tshift/ && $3 != \\\"supplied\\\" { $3=a } { print }' $config_file > tmp && mv tmp $config_file\\n\")\n", + "text_file2.write(\" $pythonscript $pythonfile -c $config_file \\n\")\n", + "text_file2.write(\"done\\n\")\n", + "text_file2.write(\"awk -v a=\\\"0\\\" '/^tshift/ && $3 != \\\"supplied\\\" { $3=a } { print }' $config_file > tmp && mv tmp $config_file \\n\")\n", + "text_file2.write(\"\\n\")\n", + "text_file2.close()\n", + "os.system('chmod u+x %s'%filename2)\n", + "\n", + "os.system('cp '+runname+'.sh %s/'%run_dir)\n", + "os.system('chmod u+x ./'+runname+'.sh')\n", + "os.system('cd '+run_dir)\n", + "\n", + "###########################################################\n", + "# Checking the configuration file and adding some important replacements\n", + "############################################################\n", + "\n", + "filename3 = '%s/%s'%(run_dir,config_file)\n", + "# change the number of cores\n", + "bashCommand = \"awk -v a=\"+str(cpus)+\" '/^nb_cores/ && $3 != \\\"supplied\\\" { $3=a } { print }' \"+str(config_file)+\" > tmp && mv tmp \"+str(config_file);\n", + "subprocess.call(bashCommand,shell=True)\n", + "\n", + "filename3 = '%s/%s'%(run_dir,config_file)\n", + "# change the number of nmax\n", + "bashCommand = \"awk -v a=\"+str(nmax)+\" '/^nmax/ && $3 != \\\"supplied\\\" { $3=a } { print }' \"+str(config_file)+\" > tmp && mv tmp \"+str(config_file);\n", + "subprocess.call(bashCommand,shell=True)\n", + "\n", + "filename3 = '%s/%s'%(run_dir,config_file)\n", + "# change the number of nmax\n", + "bashCommand = \"awk -v a=\"+str(nlive_points)+\" '/^npoints/ && $3 != \\\"supplied\\\" { $3=a } { print }' \"+str(config_file)+\" > tmp && mv tmp \"+str(config_file);\n", + "subprocess.call(bashCommand,shell=True)\n", + "\n", + "# change the overwrite parameter\n", + "bashCommand = \"awk -v a=\"+str(overwrite)+\" '/^overwrite/ && $3 != \\\"supplied\\\" { $3=a } { print }' \"+str(config_file)+\" > tmp && mv tmp \"+str(config_file);\n", + "subprocess.call(bashCommand,shell=True)\n", + " \n", + "\n", + "###########################################################\n", + "# Submit the job\n", + "############################################################\n", + "filename4 = '%s/%s'%(run_dir,'condor_submit.sub')\n", + "bashCommand = ['condor_submit', str(filename4)]\n", + "process = subprocess.Popen(bashCommand, stdout=subprocess.PIPE,stderr=subprocess.PIPE);\n", + "output,error = process.communicate()\n", + "error" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.7" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/code_new/RD_Dynesty_Fits/build/lib/RD-Dynesty-Fits/RD-Dynesty-Fits.py b/code_new/RD_Dynesty_Fits/build/lib/RD-Dynesty-Fits/RD-Dynesty-Fits.py new file mode 100644 index 0000000000000000000000000000000000000000..a8d13aac0567fe30ada2a645e23ee07072da0079 --- /dev/null +++ b/code_new/RD_Dynesty_Fits/build/lib/RD-Dynesty-Fits/RD-Dynesty-Fits.py @@ -0,0 +1,390 @@ +#!/usr/bin/env python +# coding: utf-8 + +# In[38]: + + +"""Generate ringdown templates in the time and perform parameter estimation on them. +""" + + +# In[1]: + + +#Import relevant modules, import data and all that +import time +import numpy as np +import corner +import matplotlib.pyplot as plt +from matplotlib.ticker import MaxNLocator +from matplotlib import rc +from configparser import ConfigParser +plt.rcParams.update({'font.size': 16.5}) + +from multiprocessing import Pool +import random +import dynesty +from dynesty import plotting as dyplot +from dynesty.utils import resample_equal +from dynesty import utils as dyfunc +import os +import argparse +import scipy.optimize as optimization +from scipy.optimize import minimize +import rdown as rd +import rdown_pe as rd_pe +import rdown_utilities as rd_ut +import read_data as rdata + + +# In[2]: + + +## Loading and running data tested with NR data +## Loading and running data tested with Mock data + + +# In[3]: + + +# Cell that calls the arguments from your 'config.ini' file. +try: + parser = argparse.ArgumentParser(description="Simple argument parser") + parser.add_argument("-c", action="store", dest="config_file") + result = parser.parse_args() + config_file=result.config_file + parser = ConfigParser() + parser.read(config_file) + parser.sections() +except SystemExit: + parser = ConfigParser() + parser.read('./run_0_mock/config_n0_to_1_mock.ini') + parser.sections() + pass + + +# In[4]: + + +# Load variables from config file +(simulation_path_1,simulation_path_2, metadata_file , simulation_number, output_folder, + export, overwrite, sampler,nr_code, nbcores,tshift,tend,t_align, + nmax , npoints, model, error_str, fitnoise, l_int, index_mass,index_spin, +error_type, error_val, af, mf,tau_var_str,nm_mock)=rdata.read_config_file(parser) + + +# In[5]: + + +# Show configuration options +dim = nmax+1 +ndim = 4*dim +numbins = 32 #corner plot parameter - how many bins you want + +print('model:',model) +print('nmax:',nmax) +print('nm_mock:',nm_mock) +print('tshift:',tshift) +print('error:', error_str) +print('error value:',error_val) +print('export:',export) +print('nr code:',nr_code) +print('fit noise:',fitnoise) + + +# In[6]: + + +# Create output directories +if not os.path.exists(output_folder): + os.mkdir(output_folder) + print("Directory " , output_folder , " Created ") + +if nr_code == 'Mock-data': + nm_mock_str = 'rec_with'+parser.get('rd-mock-parameters','nm_mock')+'_' +else: + nm_mock_str='' + +if error_str: + output_folder_1=(output_folder+'/'+model+'-nmax'+str(nmax)+'_'+nm_mock_str+str(error_str)+'_'+str(error_type)+'_fitnoise_'+str(fitnoise)) +else: + output_folder_1=output_folder+'/'+model+'-nmax'+str(nmax)+'_'+nm_mock_str+str(error_str)+'_'+'fitnoise_'+str(fitnoise) + +if not os.path.exists(output_folder_1): + os.mkdir(output_folder_1) + print("Directory " , output_folder_1 , " Created ") + + +# In[7]: + + +# Define output files +pars = [simulation_number,model,nmax,tshift,npoints] +corner_plot = rdata.create_output_files(output_folder_1,pars,'corner_plot') +corner_plot_extra = rdata.create_output_files(output_folder_1,pars,'corner_plot_extra') +diagnosis_plot = rdata.create_output_files(output_folder_1,pars,'diagnosis') +fit_plot = rdata.create_output_files(output_folder_1,pars,'fit') +samples_file = rdata.create_output_files(output_folder_1,pars,'post_samples') +results_file = rdata.create_output_files(output_folder_1,pars,'sampler_results') +sumary_data = rdata.create_output_files(output_folder_1,pars,'log_z') +best_data = rdata.create_output_files(output_folder_1,pars,'best_vals') + +files = [corner_plot,corner_plot_extra,diagnosis_plot,fit_plot,samples_file,results_file,sumary_data,best_data] + + +# In[8]: + + +# Remove old files if overwrite = True +if overwrite: + rd_ut.rm_files(files) + + +# In[46]: + + +#Load NR data, align in time and resize. Plot real part and amplitude. Finally compute the mismatch and the snr estimate +data = rdata.read_data(nr_code,simulation_path_1,RD=True,tshift=tshift,tend = tend,metadata_file=metadata_file,parser=parser) +data_l = rdata.read_data(nr_code,simulation_path_2,RD=True,tshift=tshift,tend = tend,metadata_file=metadata_file,parser=parser) +data_r, data_lr = rdata.nr_resize(data,data_l,tshift=tshift,tend=tend) +times_rd = data_r[:,0] + +plt.figure(figsize = (12, 8)) +plt.plot(times_rd, data_r[:,1].real, "r", alpha=0.3, lw=3, label=r'$Lev6$: real') +plt.plot(times_rd, np.sqrt((data_r[:,1].real)**2+(data_r[:,1].imag)**2), "r", alpha=0.3, lw=3, label=r'$Lev5\,amp$') +plt.plot(times_rd, data_lr[:,1].real, "b", alpha=0.3, lw=3, label=r'$Lev5: real$') +plt.plot(times_rd, np.sqrt((data_lr[:,1].real)**2+(data_lr[:,1].imag)**2), "b", alpha=0.3, lw=3, label=r'$Lev5\,amp$') +if error_str and error_val==0: + error = np.sqrt(data_r[:,1]*data_r[:,1]-2*data_r[:,1]*data_lr[:,1]+data_lr[:,1]*data_lr[:,1]) + error_est=np.sqrt(error.imag**2+error.real**2) + plt.plot(times_rd, error_est, "g", alpha=0.3, lw=2, label='error') +plt.legend() + +mismatch=1-rd_ut.EasyMatchT(times_rd,data_r[:,1],data_lr[:,1],tshift,tend) +error=np.sqrt(2*mismatch) +print('error estimate:',error) +print('mismatch:', mismatch) +print('snr:', rd_ut.EasySNRT(times_rd,data_r[:,1],data_lr[:,1],tshift,tend)/error**2) + + +# In[47]: + + +# Phase alignement +if parser.has_option('rd-model','phase_alignment'): + phase_alignment=eval(parser.get('rd-model','phase_alignment')) +else: + phase_alignment=False + +if phase_alignment: + datar_al = rdata.phase_align(data_r,data_lr) + gwdatanew5 = data_lr[:,1] + gwdatanew = datar_al[:,1] + timesrd_final = datar_al[:,0] + mismatch=1-rd_ut.EasyMatchT(timesrd_final,gwdatanew,gwdatanew5,tshift,tend) + error=np.sqrt(2*mismatch) + print('error estimate:',error) + print('mismatch:', mismatch) + print('snr:', rd_ut.EasySNRT(timesrd_final,gwdatanew,gwdatanew5,tshift,tend)/error) + if error_str: + error = np.sqrt(gwdatanew*gwdatanew-2*gwdatanew*gwdatanew5+gwdatanew5*gwdatanew5) + error_est=np.sqrt(error.imag**2+error.real**2) + else : + error = 1 +else: + datar_al = data_r + timesrd_final = datar_al[:,0] + +#Test the new interpolated data +if error_str and error_val==0: + plt.figure(figsize = (12, 8)) + plt.plot(timesrd_final, datar_al[:,1].real, "r", alpha=0.3, lw=2, label='Original') + plt.plot(timesrd_final, data_lr[:,1].real, "b", alpha=0.3, lw=2, label='Aligned') + plt.plot(timesrd_final, error_est, "b", alpha=0.3, lw=2, label='error') + plt.legend() + + +# In[48]: + + +# Define your noise depending on the noise configuration. Load priors and setup the likelihood with rd_pe.Ringdown_PE. +if error_str and error_val==0: + error_final = error_est + norm_factor = 100*len(error_final)/2*np.log(2*np.pi) +elif error_str and error_val!=0: + datar_al[:,1]+=random.uniform(0, error_val) + datar_al[:,1]+=1j*random.uniform(0, error_val) + error_tsh = error_val + error_final=(error_tsh.real**2+error_tsh.imag**2) + norm_factor = 0 +else: + error_tsh=1 + error_final=(error_tsh.real**2+error_tsh.imag**2) + norm_factor = 0 + +priors = rd_pe.load_priors(model,parser,nmax,fitnoise=fitnoise) +rdown=rd.Ringdown_Spectrum(mf,af,2,2,n=nmax,s=-2,time=timesrd_final) +rdown_pe = rd_pe.Ringdown_PE(rdown,datar_al,dim,priors,errors2=error_final,norm_factor=norm_factor,model=model,l_int=l_int) + + +# In[49]: + + +# Get a first estimate by trying to fit the data. +nll = lambda *args: -rdown_pe.log_likelihood(*args) +if model == 'w-tau-fixed-m-af': + if fitnoise: + initial = np.concatenate((np.ones(2*dim),[0.8,0.9,1])) + soln = minimize(nll, initial,bounds=priors) + vars_ml=soln.x + else: + initial = np.concatenate((np.ones(2*dim),[0.8,0.9])) + soln = minimize(nll, initial,bounds=priors) + vars_ml=soln.x +elif model == 'w-tau-fixed': + if fitnoise: + initial = np.concatenate((np.ones(2*dim),[0.2])) + soln = minimize(nll, initial,bounds=priors) + vars_ml=soln.x + else: + initial = np.ones(2*dim) + soln = minimize(nll, initial,bounds=priors) + vars_ml=soln.x +else: + if fitnoise: + initial = np.concatenate((np.ones(ndim),[1])) + soln = minimize(nll, initial,bounds=priors) + vars_ml=soln.x + else: + initial = np.ones(ndim) + soln = minimize(nll, initial,bounds=priors) + vars_ml=soln.x +print("best fit pars from fit: ",vars_ml) + + +# In[50]: + + +mypool = Pool(nbcores) +mypool.size = nbcores + +start = time.process_time() +f2=dynesty.NestedSampler(rdown_pe.log_likelihood,rdown_pe.prior_transform, len(priors), nlive=npoints,sample=sampler,pool=mypool) +if parser.has_option('setup','dlogz'): + dlogz=np.float(parser.get('setup','dlogz')) + f2.run_nested(dlogz=dlogz,print_progress=False) +else: + f2.run_nested(print_progress=False) + +print(time.process_time() - start) + + +# In[52]: + + +res = f2.results +res.samples_u.shape +res.summary() +samps=f2.results.samples +postsamps = rd_ut.posterior_samples(f2) +samps_tr=np.transpose(samps) +half_points=int(round((len(samps_tr[0])/1.25))) +evidence = res.logz[-1] +evidence_error = res.logzerr[-1] +if export: + rd_ut.save_object(res, results_file) + + +# In[53]: + + +pars = nmax,model,samps_tr, half_points +npamps = rd_ut.get_best_amps(pars,parser=parser,nr_code=nr_code) + + +# In[54]: + + +if export: + pars = simulation_number, nmax, tshift, evidence, evidence_error + rd_ut.export_logz_files(sumary_data,pars) + + +# In[55]: + + +labels = rd_ut.define_labels(dim,model,fitnoise) +if export: + pars = tshift, len(priors), labels + rd_ut.export_bestvals_files(best_data,postsamps,pars) + + +# In[56]: + + +w, tau = rdown.QNM_spectrum() +pars = w, tau, mf, af, npamps +truths = rd_ut.get_truths(model,pars,fitnoise) + + +# In[57]: + + +fg=corner.corner(postsamps,quantiles=[0.05,0.5,0.95],show_titles=True,max_n_ticks = 4,bins=50,truths=truths,labels=labels,truth_color='red') +plt.show() +if export: + fg.savefig(corner_plot, format = 'png', bbox_inches = 'tight') + + +# In[58]: + + +from importlib import reload +reload(rd_ut) +if model == 'w-tau-fixed-m-af' and export == True: + truths=np.concatenate((w,tau)) + labels_mf = np.concatenate((w_lab,tau_lab)) + new_samples = rd_ut.convert_m_af_2_w_tau_post(res,fitnoise=False) + figure = corner.corner(new_samples,truths=truths,quantiles=[0.05,0.95],labels=labels_mf,smooth=True,color='b',truth_color='r',show_titles=True) + figure.savefig(corner_plot_extra, format = 'png', bbox_inches = 'tight') + + +# In[151]: + + +#lnz_truth = ndim * -np.log(2 * 10.) # analytic evidence solution +fig, axes = dyplot.runplot(res) +fig.tight_layout() +if export: + fig.savefig(diagnosis_plot, format = 'png', dpi = 384, bbox_inches = 'tight') + + +# In[166]: + + +if export: + dict = {'w-tau':rdown.rd_model_wtau , 'w-q': rdown.rd_model_wq, 'w-tau-fixed':rdown.rd_model_wtau_fixed,'w-tau-fixed-m-af': rdown.rd_model_wtau_m_af} + figband = plt.figure(figsize = (12, 9)) + plt.plot(datar_al[:,0].real,datar_al[:,1].real, "green", alpha=0.9, lw=3, label=r'$res_{240}$') + onesig_bounds = np.array([np.percentile(postsamps[:, i], [5, 95]) for i in range(len(postsamps[0]))]).T + samples_1sigma = filter(lambda sample: np.all(onesig_bounds[0] <= sample) and np.all(sample <= onesig_bounds[1]), postsamps) + samples_1sigma_down = list(samples_1sigma)[::downfactor] + for sample in samples_1sigma_down: + plt.plot(datar_al[:,0].real, dict[model](sample).real, "r-", alpha=0.1, lw=1) + plt.title(r'Comparison of the MC fit data and the $1-\sigma$ error band') + plt.legend() + plt.xlabel('t') + plt.ylabel('h') + plt.show() + figband.savefig(fit_plot) + + +# In[162]: + + +if export: + with open(samples_file,'w') as file: + writer = csv.writer(file) + writer.writerow(labels) + writer.writerows(samps[::downfactor]) + diff --git a/code_new/RD_Dynesty_Fits/build/lib/RD-Dynesty-Fits/RD_Fits.py b/code_new/RD_Dynesty_Fits/build/lib/RD-Dynesty-Fits/RD_Fits.py new file mode 100644 index 0000000000000000000000000000000000000000..a8d13aac0567fe30ada2a645e23ee07072da0079 --- /dev/null +++ b/code_new/RD_Dynesty_Fits/build/lib/RD-Dynesty-Fits/RD_Fits.py @@ -0,0 +1,390 @@ +#!/usr/bin/env python +# coding: utf-8 + +# In[38]: + + +"""Generate ringdown templates in the time and perform parameter estimation on them. +""" + + +# In[1]: + + +#Import relevant modules, import data and all that +import time +import numpy as np +import corner +import matplotlib.pyplot as plt +from matplotlib.ticker import MaxNLocator +from matplotlib import rc +from configparser import ConfigParser +plt.rcParams.update({'font.size': 16.5}) + +from multiprocessing import Pool +import random +import dynesty +from dynesty import plotting as dyplot +from dynesty.utils import resample_equal +from dynesty import utils as dyfunc +import os +import argparse +import scipy.optimize as optimization +from scipy.optimize import minimize +import rdown as rd +import rdown_pe as rd_pe +import rdown_utilities as rd_ut +import read_data as rdata + + +# In[2]: + + +## Loading and running data tested with NR data +## Loading and running data tested with Mock data + + +# In[3]: + + +# Cell that calls the arguments from your 'config.ini' file. +try: + parser = argparse.ArgumentParser(description="Simple argument parser") + parser.add_argument("-c", action="store", dest="config_file") + result = parser.parse_args() + config_file=result.config_file + parser = ConfigParser() + parser.read(config_file) + parser.sections() +except SystemExit: + parser = ConfigParser() + parser.read('./run_0_mock/config_n0_to_1_mock.ini') + parser.sections() + pass + + +# In[4]: + + +# Load variables from config file +(simulation_path_1,simulation_path_2, metadata_file , simulation_number, output_folder, + export, overwrite, sampler,nr_code, nbcores,tshift,tend,t_align, + nmax , npoints, model, error_str, fitnoise, l_int, index_mass,index_spin, +error_type, error_val, af, mf,tau_var_str,nm_mock)=rdata.read_config_file(parser) + + +# In[5]: + + +# Show configuration options +dim = nmax+1 +ndim = 4*dim +numbins = 32 #corner plot parameter - how many bins you want + +print('model:',model) +print('nmax:',nmax) +print('nm_mock:',nm_mock) +print('tshift:',tshift) +print('error:', error_str) +print('error value:',error_val) +print('export:',export) +print('nr code:',nr_code) +print('fit noise:',fitnoise) + + +# In[6]: + + +# Create output directories +if not os.path.exists(output_folder): + os.mkdir(output_folder) + print("Directory " , output_folder , " Created ") + +if nr_code == 'Mock-data': + nm_mock_str = 'rec_with'+parser.get('rd-mock-parameters','nm_mock')+'_' +else: + nm_mock_str='' + +if error_str: + output_folder_1=(output_folder+'/'+model+'-nmax'+str(nmax)+'_'+nm_mock_str+str(error_str)+'_'+str(error_type)+'_fitnoise_'+str(fitnoise)) +else: + output_folder_1=output_folder+'/'+model+'-nmax'+str(nmax)+'_'+nm_mock_str+str(error_str)+'_'+'fitnoise_'+str(fitnoise) + +if not os.path.exists(output_folder_1): + os.mkdir(output_folder_1) + print("Directory " , output_folder_1 , " Created ") + + +# In[7]: + + +# Define output files +pars = [simulation_number,model,nmax,tshift,npoints] +corner_plot = rdata.create_output_files(output_folder_1,pars,'corner_plot') +corner_plot_extra = rdata.create_output_files(output_folder_1,pars,'corner_plot_extra') +diagnosis_plot = rdata.create_output_files(output_folder_1,pars,'diagnosis') +fit_plot = rdata.create_output_files(output_folder_1,pars,'fit') +samples_file = rdata.create_output_files(output_folder_1,pars,'post_samples') +results_file = rdata.create_output_files(output_folder_1,pars,'sampler_results') +sumary_data = rdata.create_output_files(output_folder_1,pars,'log_z') +best_data = rdata.create_output_files(output_folder_1,pars,'best_vals') + +files = [corner_plot,corner_plot_extra,diagnosis_plot,fit_plot,samples_file,results_file,sumary_data,best_data] + + +# In[8]: + + +# Remove old files if overwrite = True +if overwrite: + rd_ut.rm_files(files) + + +# In[46]: + + +#Load NR data, align in time and resize. Plot real part and amplitude. Finally compute the mismatch and the snr estimate +data = rdata.read_data(nr_code,simulation_path_1,RD=True,tshift=tshift,tend = tend,metadata_file=metadata_file,parser=parser) +data_l = rdata.read_data(nr_code,simulation_path_2,RD=True,tshift=tshift,tend = tend,metadata_file=metadata_file,parser=parser) +data_r, data_lr = rdata.nr_resize(data,data_l,tshift=tshift,tend=tend) +times_rd = data_r[:,0] + +plt.figure(figsize = (12, 8)) +plt.plot(times_rd, data_r[:,1].real, "r", alpha=0.3, lw=3, label=r'$Lev6$: real') +plt.plot(times_rd, np.sqrt((data_r[:,1].real)**2+(data_r[:,1].imag)**2), "r", alpha=0.3, lw=3, label=r'$Lev5\,amp$') +plt.plot(times_rd, data_lr[:,1].real, "b", alpha=0.3, lw=3, label=r'$Lev5: real$') +plt.plot(times_rd, np.sqrt((data_lr[:,1].real)**2+(data_lr[:,1].imag)**2), "b", alpha=0.3, lw=3, label=r'$Lev5\,amp$') +if error_str and error_val==0: + error = np.sqrt(data_r[:,1]*data_r[:,1]-2*data_r[:,1]*data_lr[:,1]+data_lr[:,1]*data_lr[:,1]) + error_est=np.sqrt(error.imag**2+error.real**2) + plt.plot(times_rd, error_est, "g", alpha=0.3, lw=2, label='error') +plt.legend() + +mismatch=1-rd_ut.EasyMatchT(times_rd,data_r[:,1],data_lr[:,1],tshift,tend) +error=np.sqrt(2*mismatch) +print('error estimate:',error) +print('mismatch:', mismatch) +print('snr:', rd_ut.EasySNRT(times_rd,data_r[:,1],data_lr[:,1],tshift,tend)/error**2) + + +# In[47]: + + +# Phase alignement +if parser.has_option('rd-model','phase_alignment'): + phase_alignment=eval(parser.get('rd-model','phase_alignment')) +else: + phase_alignment=False + +if phase_alignment: + datar_al = rdata.phase_align(data_r,data_lr) + gwdatanew5 = data_lr[:,1] + gwdatanew = datar_al[:,1] + timesrd_final = datar_al[:,0] + mismatch=1-rd_ut.EasyMatchT(timesrd_final,gwdatanew,gwdatanew5,tshift,tend) + error=np.sqrt(2*mismatch) + print('error estimate:',error) + print('mismatch:', mismatch) + print('snr:', rd_ut.EasySNRT(timesrd_final,gwdatanew,gwdatanew5,tshift,tend)/error) + if error_str: + error = np.sqrt(gwdatanew*gwdatanew-2*gwdatanew*gwdatanew5+gwdatanew5*gwdatanew5) + error_est=np.sqrt(error.imag**2+error.real**2) + else : + error = 1 +else: + datar_al = data_r + timesrd_final = datar_al[:,0] + +#Test the new interpolated data +if error_str and error_val==0: + plt.figure(figsize = (12, 8)) + plt.plot(timesrd_final, datar_al[:,1].real, "r", alpha=0.3, lw=2, label='Original') + plt.plot(timesrd_final, data_lr[:,1].real, "b", alpha=0.3, lw=2, label='Aligned') + plt.plot(timesrd_final, error_est, "b", alpha=0.3, lw=2, label='error') + plt.legend() + + +# In[48]: + + +# Define your noise depending on the noise configuration. Load priors and setup the likelihood with rd_pe.Ringdown_PE. +if error_str and error_val==0: + error_final = error_est + norm_factor = 100*len(error_final)/2*np.log(2*np.pi) +elif error_str and error_val!=0: + datar_al[:,1]+=random.uniform(0, error_val) + datar_al[:,1]+=1j*random.uniform(0, error_val) + error_tsh = error_val + error_final=(error_tsh.real**2+error_tsh.imag**2) + norm_factor = 0 +else: + error_tsh=1 + error_final=(error_tsh.real**2+error_tsh.imag**2) + norm_factor = 0 + +priors = rd_pe.load_priors(model,parser,nmax,fitnoise=fitnoise) +rdown=rd.Ringdown_Spectrum(mf,af,2,2,n=nmax,s=-2,time=timesrd_final) +rdown_pe = rd_pe.Ringdown_PE(rdown,datar_al,dim,priors,errors2=error_final,norm_factor=norm_factor,model=model,l_int=l_int) + + +# In[49]: + + +# Get a first estimate by trying to fit the data. +nll = lambda *args: -rdown_pe.log_likelihood(*args) +if model == 'w-tau-fixed-m-af': + if fitnoise: + initial = np.concatenate((np.ones(2*dim),[0.8,0.9,1])) + soln = minimize(nll, initial,bounds=priors) + vars_ml=soln.x + else: + initial = np.concatenate((np.ones(2*dim),[0.8,0.9])) + soln = minimize(nll, initial,bounds=priors) + vars_ml=soln.x +elif model == 'w-tau-fixed': + if fitnoise: + initial = np.concatenate((np.ones(2*dim),[0.2])) + soln = minimize(nll, initial,bounds=priors) + vars_ml=soln.x + else: + initial = np.ones(2*dim) + soln = minimize(nll, initial,bounds=priors) + vars_ml=soln.x +else: + if fitnoise: + initial = np.concatenate((np.ones(ndim),[1])) + soln = minimize(nll, initial,bounds=priors) + vars_ml=soln.x + else: + initial = np.ones(ndim) + soln = minimize(nll, initial,bounds=priors) + vars_ml=soln.x +print("best fit pars from fit: ",vars_ml) + + +# In[50]: + + +mypool = Pool(nbcores) +mypool.size = nbcores + +start = time.process_time() +f2=dynesty.NestedSampler(rdown_pe.log_likelihood,rdown_pe.prior_transform, len(priors), nlive=npoints,sample=sampler,pool=mypool) +if parser.has_option('setup','dlogz'): + dlogz=np.float(parser.get('setup','dlogz')) + f2.run_nested(dlogz=dlogz,print_progress=False) +else: + f2.run_nested(print_progress=False) + +print(time.process_time() - start) + + +# In[52]: + + +res = f2.results +res.samples_u.shape +res.summary() +samps=f2.results.samples +postsamps = rd_ut.posterior_samples(f2) +samps_tr=np.transpose(samps) +half_points=int(round((len(samps_tr[0])/1.25))) +evidence = res.logz[-1] +evidence_error = res.logzerr[-1] +if export: + rd_ut.save_object(res, results_file) + + +# In[53]: + + +pars = nmax,model,samps_tr, half_points +npamps = rd_ut.get_best_amps(pars,parser=parser,nr_code=nr_code) + + +# In[54]: + + +if export: + pars = simulation_number, nmax, tshift, evidence, evidence_error + rd_ut.export_logz_files(sumary_data,pars) + + +# In[55]: + + +labels = rd_ut.define_labels(dim,model,fitnoise) +if export: + pars = tshift, len(priors), labels + rd_ut.export_bestvals_files(best_data,postsamps,pars) + + +# In[56]: + + +w, tau = rdown.QNM_spectrum() +pars = w, tau, mf, af, npamps +truths = rd_ut.get_truths(model,pars,fitnoise) + + +# In[57]: + + +fg=corner.corner(postsamps,quantiles=[0.05,0.5,0.95],show_titles=True,max_n_ticks = 4,bins=50,truths=truths,labels=labels,truth_color='red') +plt.show() +if export: + fg.savefig(corner_plot, format = 'png', bbox_inches = 'tight') + + +# In[58]: + + +from importlib import reload +reload(rd_ut) +if model == 'w-tau-fixed-m-af' and export == True: + truths=np.concatenate((w,tau)) + labels_mf = np.concatenate((w_lab,tau_lab)) + new_samples = rd_ut.convert_m_af_2_w_tau_post(res,fitnoise=False) + figure = corner.corner(new_samples,truths=truths,quantiles=[0.05,0.95],labels=labels_mf,smooth=True,color='b',truth_color='r',show_titles=True) + figure.savefig(corner_plot_extra, format = 'png', bbox_inches = 'tight') + + +# In[151]: + + +#lnz_truth = ndim * -np.log(2 * 10.) # analytic evidence solution +fig, axes = dyplot.runplot(res) +fig.tight_layout() +if export: + fig.savefig(diagnosis_plot, format = 'png', dpi = 384, bbox_inches = 'tight') + + +# In[166]: + + +if export: + dict = {'w-tau':rdown.rd_model_wtau , 'w-q': rdown.rd_model_wq, 'w-tau-fixed':rdown.rd_model_wtau_fixed,'w-tau-fixed-m-af': rdown.rd_model_wtau_m_af} + figband = plt.figure(figsize = (12, 9)) + plt.plot(datar_al[:,0].real,datar_al[:,1].real, "green", alpha=0.9, lw=3, label=r'$res_{240}$') + onesig_bounds = np.array([np.percentile(postsamps[:, i], [5, 95]) for i in range(len(postsamps[0]))]).T + samples_1sigma = filter(lambda sample: np.all(onesig_bounds[0] <= sample) and np.all(sample <= onesig_bounds[1]), postsamps) + samples_1sigma_down = list(samples_1sigma)[::downfactor] + for sample in samples_1sigma_down: + plt.plot(datar_al[:,0].real, dict[model](sample).real, "r-", alpha=0.1, lw=1) + plt.title(r'Comparison of the MC fit data and the $1-\sigma$ error band') + plt.legend() + plt.xlabel('t') + plt.ylabel('h') + plt.show() + figband.savefig(fit_plot) + + +# In[162]: + + +if export: + with open(samples_file,'w') as file: + writer = csv.writer(file) + writer.writerow(labels) + writer.writerows(samps[::downfactor]) + diff --git a/code_new/RD_Dynesty_Fits/build/lib/RD-Dynesty-Fits/__init__.py b/code_new/RD_Dynesty_Fits/build/lib/RD-Dynesty-Fits/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..8b137891791fe96927ad78e64b0aad7bded08bdc --- /dev/null +++ b/code_new/RD_Dynesty_Fits/build/lib/RD-Dynesty-Fits/__init__.py @@ -0,0 +1 @@ + diff --git a/code_new/RD_Dynesty_Fits/build/lib/RD-Dynesty-Fits/rdown.py b/code_new/RD_Dynesty_Fits/build/lib/RD-Dynesty-Fits/rdown.py new file mode 100644 index 0000000000000000000000000000000000000000..1357ccbf98a454670c79fb49574d7fe1447e243a --- /dev/null +++ b/code_new/RD_Dynesty_Fits/build/lib/RD-Dynesty-Fits/rdown.py @@ -0,0 +1,208 @@ +# Copyright (C) 2021 Xisco Jimenez Forteza +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + +# +# ============================================================================= +# +# Preamble +# +# ============================================================================= +# +# Module to generate RD waveforms. + +import numpy as np +import qnm +import os + +f_fpars= [[2.95845, -2.58697, 0.0533469], [2.12539, -1.78054, 0.0865503], [1.74755, -1.44776, 0.123666], [1.78287, -1.53203, 0.129475], [2.04028, -1.83224, 0.112497]] +q_fpars=[[0.584077, 1.52053, -0.480658], [0.00561441, 0.630715, -0.432664], [-0.197965, 0.515956, -0.369706], [-0.275097, 0.455691, -0.331543], [-0.287596, 0.398514, -0.309799]] + + +c=2.99792458*10**8;G=6.67259*10**(-11);MS=1.9885*10**30; +class Ringdown_Spectrum: + """RDown model generator""" + def __init__(self,mf,af,l,m,n=4,s=-2,time=[],fixed=False,qnm_model='berti'): + self.mf = mf + self.af = af + self.l = l + self.m = m + self.n = n + self.time = time + self.grav_220 = [qnm.modes_cache(s=s,l=self.l,m=self.m,n=i) for i in range (0,self.n+1)] + self.dim = self.n+1 + self.fixed = fixed + self.qnm_model = qnm_model + dict_omega = {'berti': self.QNM_Berti , 'qnm': self.QNM_spectrum} + dic = {'w-tau':self.rd_model_wtau , 'w-q': self.rd_model_wq, 'w-tau-fixed':self.rd_model_wtau_fixed,'w-tau-fixed-m-af': self.rd_model_wtau_m_af} + + if len(self.time)==0: + self.time = np.arange(0,100,0.1) + + if self.fixed: + omegas_new=np.asarray([self.grav_220[i](a=self.af)[0] for i in range (0,self.dim)]) + self.w = (np.real(omegas_new))/self.mf + self.tau=-1/(np.imag(omegas_new))*self.mf + + + def QNM_spectrum(self): + """ It computes the RD frequencies and damping times in NR units. + """ + omegas_new=np.asarray([self.grav_220[i](a=self.af)[0] for i in range (0,self.n+1)]) + w_m_a = (np.real(omegas_new))/self.mf + tau_m_a=-1/(np.imag(omegas_new))*self.mf + + return (w_m_a, tau_m_a) + + def QNM_Berti(self,rdowndata): + """ It computes the RD frequencies and damping times in NR units. + """ + position=np.argmax(rdowndata[0,0] >= (self.af)) + #w_m_a=f1+f2*(1-af)**f3 + w_m_a=[None]*(self.n+1) + tau_ma_a=[None]*(self.n+1) + + for i in range(self.n+1): + qnm=rdowndata[i,1:3,position] + w_m_a[i] = qnm[0]/self.mf + tau_ma_a[i] = -1/(qnm[1])*self.mf + + return w_m_a, tau_ma_a + + + def w_fpars_Berti(self,n): + return f_fpars[n] + + def tau_qpars_Berti(self,n): + return q_fpars[n] + + def mass_from_wtau(self,n,w,tau): + f1,f2,f3 = w_fpars_Berti(n) + q1,q2,q3 = tau_qpars_Berti(n) + res=(f1 + f2*(2**(-1/q3)*((-2*q1 + w*tau)/q2)**(1/q3))**f3)/w + return res + + def spin_from_wtau(self,n,w,tau): + f1,f2,f3 = w_fpars_Berti(n) + q1,q2,q3 = tau_qpars_Berti(n) + res=1 - 2**(-1/q3)*((-2*q1 + w*tau)/q2)**(1/q3) + return res + + def mass_from_wtau_loop(self,w,tau,l,m): + res=[None]*dim + for n in range (0,dim): + f1,f2,f3 = w_fpars_Berti(n) + q1,q2,q3 = tau_qpars_Berti(n) + res[n]=(f1 + f2*(2**(-1/q3)*((-2*q1 + w[n]*tau[n])/q2)**(1/q3))**f3)/w[n] + return res + + def spin_from_wtau_loop(self,w,tau,l,m): + res=[None]*dim + for n in range (0,dim): + f1,f2,f3 = w_fpars_Berti(n) + q1,q2,q3 = tau_qpars_Berti(n) + res[n]= 1 - 2**(-1/q3)*((-2*q1 + w[n]*tau[n])/q2)**(1/q3) + return res + + + def rd_model_wtau(self,theta): + """RD model parametrized with the damping time tau. + """ + assert int(len(theta)/4) == self.dim, 'Please recheck your n and parameters' + + wvars = theta[ : (self.dim)] + tvars = theta[(self.dim) : 2*(self.dim)] + xvars = theta[2*(self.dim) : 3*(self.dim)] + yvars = theta[3*(self.dim) : ] + + ansatz = 0 + for i in range (0,self.dim): + ansatz += (xvars[i]*np.exp(1j*yvars[i]))*np.exp(-self.time/tvars[i]) * (np.cos(wvars[i]*self.time)-1j*np.sin(wvars[i]*self.time)) + # -1j to agree with SXS convention + return ansatz + + def rd_model_wtau_m_af(theta): + """RD model parametrized with the damping time tau and with the QNM spectrum fixd to GR. The QNM spectrum is given from the mass and spin. + """ + xvars = theta[ : (dim)] + yvars = theta[(dim) : 2*(dim)] + mass_vars = theta[index_mass] + spin_vars = theta[index_spin] + + w_m_a , tau_m_a = dict_omega[self.qnm_model](mass_vars,spin_vars,2,2) + + ansatz = 0 + for i in range (0,dim): + ansatz += (xvars[i]*np.exp(1j*yvars[i]))*np.exp(-timesrd_final_tsh/tau_m_a[i]) * (np.cos(w_m_a[i]*timesrd_final_tsh)-1j*np.sin(w_m_a[i]*timesrd_final_tsh)) + # -1j to agree with SXS convention + return ansatz + + def rd_model_wtau_fixed(theta): + """RD model parametrized with the damping time tau and with the QNM spectrum fixd to GR. + """ + xvars = theta[ : (dim)] + yvars = theta[(dim) : 2*(dim)] + + ansatz = 0 + for i in range (0,dim): + ansatz += (xvars[i]*np.exp(1j*yvars[i]))*np.exp(-timesrd_final_tsh/tau[i]) * (np.cos(w[i]*timesrd_final_tsh)-1j*np.sin(w[i]*timesrd_final_tsh)) + # -1j to agree with SXS convention + return ansatz + + def rd_model_wq(self,theta): + """RD model parametrized with the quality factor q. + """ + assert int(len(theta)/4) == self.dim, 'Please recheck your n and parameters' + + wvars = theta[ : (self.dim)] + qvars = theta[(self.dim) : 2*(self.dim)] + xvars = theta[2*(self.dim) : 3*(self.dim)] + yvars = theta[3*(self.dim) : ] + + ansatz = 0 + for i in range (0,self.dim): + ansatz += (xvars[i]*np.exp(1j*yvars[i]))*np.exp(-self.time*np.pi*wvars[i]/qvars[i])*(np.cos(wvars[i]*self.time)-1j*np.sin(wvars[i]*self.time)) + # -1j to agree with SXS convention + return ansatz + + def rd_model_wq_fixed(self,theta): + """RD model parametrized with the damping time tau and with the QNM spectrum fixd to GR. + """ + xvars = theta[ : (self.dim)] + yvars = theta[(self.dim) : 2*(self.dim)] + + ansatz = 0 + for i in range (0,self.dim): + ansatz += (xvars[i]*np.exp(1j*yvars[i]))*np.exp(-self.time/self.tau[i]) * (np.cos(self.w[i]*self.time)-1j*np.sin(self.w[i]*self.time)) + # -1j to agree with SXS convention + return ansatz + + + def rd_model_wq_m_a(self,theta): + """RD model parametrized with the damping time tau and with the QNM spectrum fixd to GR. The QNM spectrum is given from the mass and spin. + """ + xvars = theta[ : (self.dim)] + yvars = theta[(self.dim) : 2*(self.dim)] + mass_vars = theta[-2] + spin_vars = theta[-1] + + w_m_a , tau_m_a = QNM_spectrum() + + ansatz = 0 + for i in range (0,dim): + ansatz += (xvars[i]*np.exp(1j*yvars[i]))*np.exp(-timesrd_final_tsh/tau_m_a[i]) * (np.cos(w_m_a[i]*timesrd_final_tsh)-1j*np.sin(w_m_a[i]*timesrd_final_tsh)) + # -1j to agree with SXS convention + return ansatz \ No newline at end of file diff --git a/code_new/RD_Dynesty_Fits/build/lib/RD-Dynesty-Fits/rdown_pe.py b/code_new/RD_Dynesty_Fits/build/lib/RD-Dynesty-Fits/rdown_pe.py new file mode 100644 index 0000000000000000000000000000000000000000..c92e073cac48d68b9fb46fc44a03b6e1c2c8af65 --- /dev/null +++ b/code_new/RD_Dynesty_Fits/build/lib/RD-Dynesty-Fits/rdown_pe.py @@ -0,0 +1,191 @@ +# Copyright (C) 2021 Xisco Jimenez Forteza +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + +# +# ============================================================================= +# +# Preamble +# +# ============================================================================= +# +# Module to run PE on RD data +import random +from multiprocessing import Pool +import dynesty +import numpy as np +import rdown + +class Ringdown_PE: + def __init__(self,rdown_fun,data,dim,priors,errors2=1,theta=[],model='w-tau',norm_factor=0,l_int=0): + self.dim = dim + self.rdown_fun = rdown_fun + self.times = data[:,0] + self.datare = data[:,1].real + self.dataim = data[:,1].imag + self.priors = priors + self.priors_min = priors[:,0] + self.priors_max = priors[:,1] + self.prior_dim = len(priors) + self.errors2 = errors2 + self.norm_factor = norm_factor + self.model = model + self.l_int = l_int + self.theta = theta + self.dict = {'w-tau':rdown_fun.rd_model_wtau , 'w-q': rdown_fun.rd_model_wq, 'w-tau-fixed':rdown_fun.rd_model_wtau_fixed,'w-tau-fixed-m-af': rdown_fun.rd_model_wtau_m_af} + + #def log_likelihood(self,theta,sigma=1): + # """chi2 likelihood. + # """ + # modelev = dict[model](theta) + # result = -np.sum(((gwdatanew_re_tsh - modelev.real)**2+(gwdatanew_im_tsh - modelev.imag)**2)/(2*theta[-1]*error_final)) + # if np.isnan(result): + # return -np.inf + # return result + + def log_likelihood(self,theta,sigma=1): + """chi2 likelihood. + """ + modelev = self.dict[self.model](theta) + modelevre= modelev.real + modelevim= modelev.imag + + sigma2 = self.errors2 + self.l_int*(self.datare** 2+self.dataim**2) * np.exp(2 * theta[-1]) + + result = -0.5*np.sum(((self.datare - modelevre)**2+(self.dataim - modelevim)**2)/sigma2+self.l_int*(np.log(2*np.pi*sigma2)))-self.l_int*self.norm_factor + + if np.isnan(result): + return -np.inf + return result + + + def prior_transform(self,cube): + """RD uniform priors. The values for priors_min and priors_max must be given out of this function. + """ + for i in range(self.prior_dim): + cube[i] = self.priors_min[i]+ cube[i]*(self.priors_max[i]-self.priors_min[i]) + return cube + +def load_priors(model,config_parser,nmax,fitnoise=True): + # loading priors + if model == 'w-q': + tau_var_str='q' + else: + tau_var_str='tau' + + if model == 'w-tau': + w_mins=np.empty(nmax+1) + w_maxs=np.empty(nmax+1) + tau_mins=np.empty(nmax+1) + tau_maxs=np.empty(nmax+1) + a_mins=np.empty(nmax+1) + a_maxs=np.empty(nmax+1) + ph_mins=np.empty(nmax+1) + ph_maxs=np.empty(nmax+1) + + for i in range(nmax+1): + wp_min=config_parser.get('prior-w'+str(i),'w'+str(i)+'_min') + w_mins[i] = np.float(wp_min) + + wp_max=config_parser.get('prior-w'+str(i),'w'+str(i)+'_max') + w_maxs[i] = np.float(wp_max) + + taup_min=config_parser.get('prior-'+tau_var_str+str(i),tau_var_str+str(i)+'_min') + tau_mins[i] = np.float(taup_min) + + taup_max=config_parser.get('prior-'+tau_var_str+str(i),tau_var_str+str(i)+'_max') + tau_maxs[i] = np.float(taup_max) + + amp0_min=config_parser.get('prior-amp'+str(i),'amp'+str(i)+'_min') + a_mins[i] = np.float(amp0_min) + + amp1_max=config_parser.get('prior-amp'+str(i),'amp'+str(i)+'_max') + a_maxs[i] = np.float(amp1_max) + + phase_min=config_parser.get('prior-phase'+str(i),'phase'+str(i)+'_min') + ph_mins[i] = np.float(phase_min)*2*np.pi + + phase_max=config_parser.get('prior-phase'+str(i),'phase'+str(i)+'_max') + ph_maxs[i] = np.float(phase_max)*2*np.pi + + priors_min = np.concatenate((w_mins,tau_mins,a_mins,ph_mins)) + priors_max = np.concatenate((w_maxs,tau_maxs,a_maxs,ph_maxs)) + prior_dim = len(priors_min) + priors=np.column_stack((priors_min,priors_max)) + + if model == 'w-tau-fixed': + a_mins=np.empty(nmax+1) + a_maxs=np.empty(nmax+1) + ph_mins=np.empty(nmax+1) + ph_maxs=np.empty(nmax+1) + + for i in range(nmax+1): + amp0_min=config_parser.get('prior-amp'+str(i),'amp'+str(i)+'_min') + a_mins[i] = np.float(amp0_min) + + amp1_max=config_parser.get('prior-amp'+str(i),'amp'+str(i)+'_max') + a_maxs[i] = np.float(amp1_max) + + phase_min=config_parser.get('prior-phase'+str(i),'phase'+str(i)+'_min') + ph_mins[i] = np.float(phase_min)*2*np.pi + + phase_max=config_parser.get('prior-phase'+str(i),'phase'+str(i)+'_max') + ph_maxs[i] = np.float(phase_max)*2*np.pi + + + priors_min = np.concatenate((a_mins,ph_mins)) + priors_max = np.concatenate((a_maxs,ph_maxs)) + prior_dim = len(priors_min) + priors=np.column_stack((priors_min,priors_max)) + + elif model == 'w-tau-fixed-m-af': + a_mins=np.empty(nmax+1) + a_maxs=np.empty(nmax+1) + ph_mins=np.empty(nmax+1) + ph_maxs=np.empty(nmax+1) + + for i in range(nmax+1): + amp0_min=config_parser.get('prior-amp'+str(i),'amp'+str(i)+'_min') + a_mins[i] = np.float(amp0_min) + + amp1_max=config_parser.get('prior-amp'+str(i),'amp'+str(i)+'_max') + a_maxs[i] = np.float(amp1_max) + + phase_min=config_parser.get('prior-phase'+str(i),'phase'+str(i)+'_min') + ph_mins[i] = np.float(phase_min)*2*np.pi + + phase_max=config_parser.get('prior-phase'+str(i),'phase'+str(i)+'_max') + ph_maxs[i] = np.float(phase_max)*2*np.pi + + mass_min=[np.float(config_parser.get('prior-mass','mass_min'))] + mass_max=[np.float(config_parser.get('prior-mass','mass_max'))] + spin_min=[np.float(config_parser.get('prior-spin','spin_min'))] + spin_max=[np.float(config_parser.get('prior-spin','spin_max'))] + priors_min = np.concatenate((a_mins,ph_mins,mass_min,spin_min)) + priors_max = np.concatenate((a_maxs,ph_maxs,mass_max,spin_max)) + prior_dim = len(priors_min) + priors=np.column_stack((priors_min,priors_max)) + + + if fitnoise: + priors_fit_min=[np.float(config_parser.get('prior-noise','noise_min'))] + priors_fit_max=[np.float(config_parser.get('prior-noise','noise_max'))] + priors_min = np.concatenate((priors_min,priors_fit_min)) + priors_max = np.concatenate((priors_max,priors_fit_max)) + priors=np.column_stack((priors_min,priors_max)) + prior_dim = len(priors_min) + + return priors \ No newline at end of file diff --git a/code_new/RD_Dynesty_Fits/build/lib/RD-Dynesty-Fits/rdown_utilities.py b/code_new/RD_Dynesty_Fits/build/lib/RD-Dynesty-Fits/rdown_utilities.py new file mode 100644 index 0000000000000000000000000000000000000000..c4a5b95c1c26beb418d2457fbd2a2b09212778c3 --- /dev/null +++ b/code_new/RD_Dynesty_Fits/build/lib/RD-Dynesty-Fits/rdown_utilities.py @@ -0,0 +1,318 @@ +# Copyright (C) 2021 Xisco Jimenez Forteza +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + +# +# ============================================================================= +# +# Preamble +# +# ============================================================================= +# +# Module to run PE on RD data +import numpy as np +from dynesty.utils import resample_equal +from dynesty import utils as dyfunc +import os +import csv +import pandas as pd +import pickle + +def posterior_samples(sampler): + """ + Returns posterior samples from nested samples and weights + given by dynsety sampler + """ + + dynesty_samples = sampler.results['samples'] + wt = np.exp(sampler.results['logwt'] - + sampler.results['logz'][-1]) + # Make sure that sum of weights equal to 1 + weights = wt/np.sum(wt) + posterior_dynesty = dyfunc.resample_equal(dynesty_samples, weights) + return posterior_dynesty + +def FFT_FreqBins(times): + Len = len(times) + DeltaT = times[-1]- times[0] + dt = DeltaT/(Len-1) + dnu = 1/(Len*dt) + maxfreq = 1/(2*dt) + add = dnu/4 + + p = np.arange(0.0,maxfreq+add,dnu) + m = np.arange(p[-1]-(2*maxfreq)+dnu,-dnu/2+add,dnu) + res=np.concatenate((p,m)) + + return res + +def hFromPsi4FFI(tpsi4,f0): + + timecheck1=tpsi4[-2,0]-tpsi4[-1,0] + timecheck2=tpsi4[1,0]-tpsi4[0,0] + + if np.abs(timecheck1-timecheck2)>=0.0001: + print("The data might not be equally sampled!!") + + times,data= tpsi4[:,0],tpsi4[:,1] + + freqs = FT_FreqBins(xaxis.real).real + position = np.argmax(freqs >= f0) + freqs[:position]=f0*np.ones(len(freqs[:position])) + freqs=2*np.pi*freqs + + fdata=fft(data) + len(myTable)*ifft(- fdata/floor**2); + np.stack((times,data)).T + + +def twopoint_autocovariance(t,n): + """ It computes the two-point autocovariance function. + """ + dt=t[1]-t[0] + res = np.zeros(len(n)) + taus = np.zeros(len(n)) + for tau in range(0,int(len(n)/2)): + ntau=np.roll(n, tau) + taus[tau] = t[tau] + res[tau]=np.sum(n*ntau).real + return (taus[:int(len(n)/2)],res[:int(len(n)/2)]) + +def save_object(obj, filename): + with open(filename, 'wb') as output: # Overwrites any existing file. + pickle.dump(obj, output, pickle.HIGHEST_PROTOCOL) + + +def EasyMatchT(t,h1,h2,tmin,tmax): + """ It computes the time-domain match for (h1|h2) complex waveforms. + """ + pos = np.argmax(t >= (tmin)); + + h1red=h1[pos:]; + h2red=h2[pos:]; + + norm1=np.sum(np.abs(h1red)**2) + norm2=np.sum(np.abs(h2red)**2) + + myTable=h1red*np.conjugate(h2red) + res=((np.sum(myTable)/np.sqrt(norm1*norm2))).real + + return res + +def EasySNRT(t,h1,h2,tmin,tmax): + """ It computes the time-domain snr for (h1|h2) complex waveforms. + """ + pos = np.argmax(t >= (tmin)); + + h1red=h1[pos:]; + h2red=h2[pos:]; + + myTable=h1red*np.conjugate(h2red) + res=2*np.sqrt((np.sum(myTable)).real) + + return res + +def FindTmaximum(y): + """ It determines the maximum absolute value of the complex waveform. + """ + absval = np.sqrt(y[:,1]*y[:,1]+y[:,2]*y[:,2]) + vmax=np.max(absval) + index = np.argmax(absval == vmax) + timemax=y[index,0] + + return timemax + +def export_logz_files(output_file,pars): + sim_num, nmax, tshift, evidence, evidence_error = pars + + """ + Generate the logz.csv files you want to export the data to. + file_type must be one of this options: [corner_plot,corner_plot_extra,diagnosis,fit,post_samples,sampler_results,log_z] + """ + + summary_titles=['n','id','t_shift','dlogz','dlogz_err'] + if os.path.exists(output_file): + outvalues = np.array([[nmax, sim_num, tshift, evidence,evidence_error]]) + else: + outvalues = np.array([summary_titles,[nmax, sim_num, tshift, evidence,evidence_error]]) + + with open(output_file, 'a') as file: + writer = csv.writer(file) + if (outvalues.shape)[0]>1 : + writer.writerows(outvalues) + else: + writer.writerow(outvalues[0]) + + return + +def export_bestvals_files(best_data_file,postsamps,pars): + + tshift, lenpriors, labels = pars + + sigma_vars_m = np.empty(lenpriors) + sigma_vars_p = np.empty(lenpriors) + sigma_vars = np.empty(lenpriors) + sigma_vars_ml = np.empty(lenpriors) + for i in range(lenpriors): + amps_aux = postsamps[:,i] + sigma_vars_m[i] = np.quantile(amps_aux, 0.05) + sigma_vars[i] = np.quantile(amps_aux, 0.5) + sigma_vars_ml[i] = postsamps[-1,i] + sigma_vars_p[i] = np.quantile(amps_aux, 0.95) + + sigma_vars_all = [sigma_vars,sigma_vars_ml,sigma_vars_m,sigma_vars_p] + sigma_vars_all=np.stack([sigma_vars,sigma_vars_ml,sigma_vars_m,sigma_vars_p], axis=0) + + key =['max val','max val ml','lower bound','higher bound'] + dfslist = [pd.DataFrame(np.concatenate(([tshift],sigma_vars_all[i])).reshape((-1,lenpriors+1)), columns=np.concatenate((['tshift'],labels)), index = [key[i]]) for i in range(4)] + df2 = pd.concat(dfslist) + if os.path.exists(best_data_file): + df2.to_csv(best_data_file, mode='a', header=False,index = True) + else: + df2.to_csv(best_data_file, index = True) + + + +def define_labels(dim,model,fitnoise): + wstr = r'$\omega_' + + if model == 'w-tau': + taustr = r'$\tau_' + elif model == 'w-q': + taustr = r'$q_' + elif model == 'w-tau-fixed': + taustr = r'$dumb_var}' + elif model == 'w-tau-fixed-m-af': + taustr = r'$\tau_' + + ampstr = r'$A_' + phasestr = r'$\phi_' + + w_lab = [None] * dim + tau_lab = [None] * dim + amp_lab = [None] * dim + pha_lab = [None] * dim + mass_lab = ['mass'] + spin_lab = ['spin'] + + for i in range(dim): + w_lab[i] = wstr+str(i)+'$' + tau_lab[i] = taustr+str(i)+'$' + amp_lab[i] = ampstr+str(i)+'$' + pha_lab[i] = phasestr+str(i)+'$' + + + labels = np.concatenate((w_lab,tau_lab,amp_lab,pha_lab)) + + if model=='w-tau-fixed': + labels = np.concatenate((amp_lab,pha_lab)) + + if model=='w-tau-fixed-m-af': + pha_lab[i] = phasestr+str(i)+'$' + + labels = np.concatenate((amp_lab,pha_lab,mass_lab,spin_lab)) + + if fitnoise: + noise_lab = ['noise'] + labels = np.concatenate((labels,noise_lab)) + + return labels + +def get_truths(model,pars,fitnoise): + w, tau, mf, af , npamps = pars + if model == 'w-q': + tau_val = np.pi*w*tau + truths = np.concatenate((w,tau_val,npamps)) + elif model == 'w-tau': + tau_val = tau + truths = np.concatenate((w,tau_val,npamps)) + elif model == 'w-tau-fixed': + truths = npamps + elif model == 'w-tau-fixed-m-af': + truths = np.concatenate((npamps,[mf],[af])) + + if fitnoise: + truths = np.concatenate((truths,[1])) + + return truths + +def get_best_amps(pars,parser=None,nr_code=None): + nmax,model,samps_tr,half_points = pars + + + if model=='w-tau-fixed': + rg = (nmax+1) + elif model=='w-tau-fixed': + rg = (nmax+1)+2 + else: + rg = (nmax+1)*2 + + + if model=='w-tau-fixed-a-mf': + npamps = np.empty((nmax+1)) + for i in range(0,(nmax+1)): + amps_aux = samps_tr[i+rg][half_points:-1] + npamps[i] = np.quantile(amps_aux, 0.5) + else : + npamps = np.empty((nmax+1)*2) + for i in range(0,(nmax+1)*2): + amps_aux = samps_tr[i][half_points:-1] + npamps[i] = np.quantile(amps_aux, 0.5) + + if nr_code == 'Mock-data': + nm_mock = parser.get('rd-mock-parameters','nm_mock') + nm_mock = np.int(nm_mock) + amp_mock=np.empty(nm_mock+1) + ph_mock=np.empty(nm_mock+1) + for i in range(nm_mock+1): + amp_mockp = parser.get('rd-mock-parameters','amp'+str(i)) + amp_mock[i] = np.float(amp_mockp) + ph_mockp=parser.get('rd-mock-parameters','phase'+str(i)) + ph_mock[i] = np.float(ph_mockp) + + npamps = np.concatenate((amp_mock,ph_mock)) + return npamps + +def convert_m_af_2_w_tau_post(res,fitnoise=False): + + samples_2=res.samples + samps=f2.results.samples + + if fitnoise: + fmass_spin=(samps.T)[-3:-1].T + else: + fmass_spin=(samps.T)[-2:].T + #fmass_spin=new_samples[-2:] + fmass_spin_dist=[None]*len(fmass_spin) + weight=np.exp(res.logwt - res.logz[-1]) + for i in range(len(fmass_spin)): + fmass_spin_dist[i]=np.concatenate(dict_omega[qnm_model](fmass_spin[i,0],fmass_spin[i,1],2,2)) + + fmass_spin_dist_v2=np.asarray(fmass_spin_dist) + new_samples = dyfunc.resample_equal(fmass_spin_dist_v2, weight) + + return new_samples + +def save_object(obj, filename): + with open(filename, 'wb') as output: # Overwrites any existing file. + pickle.dump(obj, output, pickle.HIGHEST_PROTOCOL) + +def rm_files(files): + """ rm all old files """ + for i in files: + if os.path.exists(i): + os.remove(i) + \ No newline at end of file diff --git a/code_new/RD_Dynesty_Fits/build/lib/RD-Dynesty-Fits/read_data.py b/code_new/RD_Dynesty_Fits/build/lib/RD-Dynesty-Fits/read_data.py new file mode 100644 index 0000000000000000000000000000000000000000..87185de6364a1b89cb9223329e31dc5bb3e58391 --- /dev/null +++ b/code_new/RD_Dynesty_Fits/build/lib/RD-Dynesty-Fits/read_data.py @@ -0,0 +1,344 @@ +# Copyright (C) 2021 Xisco Jimenez Forteza +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + +# +# ============================================================================= +# +# Preamble +# +# ============================================================================= +# +# Module to run PE on RD data +import numpy as np +import rdown_utilities as rd_ut +import romspline +import rdown as rd +import h5py +import json +from scipy import interpolate +from scipy.interpolate import interp1d + + +def read_data(nr_code,sim_path,mf=1,af=0,parser=None,RD=True,tshift=0,tend = 100,metadata_file=None): + if nr_code=='SXS': + gw = {} + gw = h5py.File(sim_path, 'r') + gw_data = gw["Extrapolated_N3.dir"]["Y_l2_m2.dat"] + times = gw_data[:,0] + + metadata = {} + with open(metadata_file) as file: + metadata = json.load(file) + + af = metadata['remnant_dimensionless_spin'][-1] + mf = metadata['remnant_mass'] + + tmax=rd_ut.FindTmaximum(gw_data[round(len(gw_data)/2):]) + times = times - tmax + + if RD: + position = np.argmax(times >= 0) + gw_data = gw_data[:,1][position:]+1j*gw_data[:,2][position:] + times = times[times >= 0] + + elif nr_code=='Maya': + dt=0.1 + gw = {} + gw = h5py.File(sim_path, 'r') + gw_sxs_bbh_0305_amp = np.asarray(gw['amp_l2_m2/Y'])[6:] + times_1 = np.asarray(gw['amp_l2_m2/X'])[6:] + gw_sxs_bbh_0305_amp_int = romspline.ReducedOrderSpline(times_1, gw_sxs_bbh_0305_amp) + gw_sxs_bbh_0305_pha = np.asarray(gw['phase_l2_m2/Y'])[6:] + times = np.asarray(gw['phase_l2_m2/X'])[6:] + gw_sxs_bbh_0305_pha_int = romspline.ReducedOrderSpline(times, gw_sxs_bbh_0305_pha) + + tmin=max(times_1[0],times[0]) + tmax=min(times_1[-1],times[-1]) + times=np.arange(tmin,tmax,dt) + amps=gw_sxs_bbh_0305_amp_int(times) + phs=gw_sxs_bbh_0305_pha_int(times) + gw_sxs_bbh_0305 = np.asarray([times,amps*np.cos(phs),amps*np.sin(phs)]).T + gw5_sxs_bbh_0305 = gw_sxs_bbh_0305 + + times = gw_sxs_bbh_0305[:,0] + tmax=rd_ut.FindTmaximum(gw_sxs_bbh_0305[round(len(gw_sxs_bbh_0305)/2):]) + times = times - tmax + + #times 6--> x axis of your data + times5 = gw5_sxs_bbh_0305[:,0] + tmax5=rd_ut.FindTmaximum(gw5_sxs_bbh_0305[round(len(gw_sxs_bbh_0305)/2):]) + times5 = times5 - tmax5 + #Select the data from 0 onwards + position = np.argmax( times >= (t_align)) + position5 = np.argmax(times5 >= (t_align)) + gw_sxs_bbh_0305rd=gw_sxs_bbh_0305[position+1:] + gw_sxs_bbh_0305rd5=gw5_sxs_bbh_0305[position5+1:] + timesrd=gw_sxs_bbh_0305[position:-1][:,0][:] + timesrd5=gw5_sxs_bbh_0305[position5:-1][:,0][:] + + elif nr_code=='LaZeV': + dt=0.1 + gw = {} + gw = h5py.File(simulation_path_1, 'r') + gw_sxs_bbh_0305_amp = np.asarray(gw['amp_l2_m2/Y'])[6:] + times_1 = np.asarray(gw['amp_l2_m2/X'])[6:] + gw_sxs_bbh_0305_amp_int = romspline.ReducedOrderSpline(times_1, gw_sxs_bbh_0305_amp) + gw_sxs_bbh_0305_pha = np.asarray(gw['phase_l2_m2/Y'])[6:] + times = np.asarray(gw['phase_l2_m2/X'])[6:] + gw_sxs_bbh_0305_pha_int = romspline.ReducedOrderSpline(times, gw_sxs_bbh_0305_pha) + + tmin=max(times_1[0],times[0]) + tmax=min(times_1[-1],times[-1]) + times=np.arange(tmin,tmax,dt) + amps=gw_sxs_bbh_0305_amp_int(times) + phs=gw_sxs_bbh_0305_pha_int(times) + gw_sxs_bbh_0305 = np.asarray([times,amps*np.cos(phs),amps*np.sin(phs)]).T + gw5_sxs_bbh_0305 = gw_sxs_bbh_0305 + + times = gw_sxs_bbh_0305[:,0] + tmax=rd_ut.FindTmaximum(gw_sxs_bbh_0305[round(len(gw_sxs_bbh_0305)/2):]) + times = times - tmax + + #times 6--> x axis of your data + times5 = gw5_sxs_bbh_0305[:,0] + tmax5=rd_ut.FindTmaximum(gw5_sxs_bbh_0305[round(len(gw_sxs_bbh_0305)/2):]) + times5 = times5 - tmax5 + + #Select the data from 0 onwards + position = np.argmax( times >= (t_align)) + position5 = np.argmax(times5 >= (t_align)) + gw_sxs_bbh_0305rd=gw_sxs_bbh_0305[position+1:] + gw_sxs_bbh_0305rd5=gw5_sxs_bbh_0305[position5+1:] + timesrd=gw_sxs_bbh_0305[position:-1][:,0][:] + timesrd5=gw5_sxs_bbh_0305[position5:-1][:,0][:] + + elif nr_code=='Mock-data': + times = np.arange(tshift,tend+10,0.1) + + nm_mock = parser.get('rd-mock-parameters','nm_mock') + nm_mock = np.int(nm_mock) + mf = parser.get('rd-mock-parameters','mf') + mf = np.float(mf) + af = np.float(parser.get('rd-mock-parameters','af')) + af = np.float(af) + + rdown=rd.Ringdown_Spectrum(mf,af,2,2,n=nm_mock,s=-2,time=times) + + w_mock=np.empty(nm_mock+1) + tau_mock=np.empty(nm_mock+1) + amp_mock=np.empty(nm_mock+1) + ph_mock=np.empty(nm_mock+1) + + for i in range(nm_mock+1): + wp_mock = parser.get('rd-mock-parameters','w'+str(i)) + w_mock[i] = np.float(wp_mock) + tp_mock=parser.get('rd-mock-parameters','tau'+str(i)) + tau_mock[i] = np.float(tp_mock) + amp_mockp = parser.get('rd-mock-parameters','amp'+str(i)) + amp_mock[i] = np.float(amp_mockp) + ph_mockp=parser.get('rd-mock-parameters','phase'+str(i)) + ph_mock[i] = np.float(ph_mockp) + + + pars = np.concatenate((w_mock,tau_mock,amp_mock,ph_mock)) + gw_data=rdown.rd_model_wtau(pars) + + return np.stack((times,gw_data)).T + +def nr_resize(data_1,data_2,tshift=0,tend=100): + times_1 = data_1[:,0].real + times_2 = data_2[:,0].real + data_1_re = data_1[:,1].real + data_1_im = data_1[:,1].imag + data_2_re = data_2[:,1].real + data_2_im = data_2[:,1].imag + + gwnew_re = interpolate.interp1d(times_1, data_1_re, kind = 'cubic') + gwnew_im = interpolate.interp1d(times_1, data_1_im, kind = 'cubic') + gwnew_re5 = interpolate.interp1d(times_2, data_2_re, kind = 'cubic') + gwnew_im5 = interpolate.interp1d(times_2, data_2_im, kind = 'cubic') + + if times_2[-1]>= times_1[-1]: + times_rd = times_1 + else: + times_rd = times_2 + + gwdatanew_re = gwnew_re(times_rd) + gwdatanew_im = gwnew_im(times_rd) + gwdatanew_re5 = gwnew_re5(times_rd) + gwdatanew_im5 = gwnew_im5(times_rd) + gwdatanew = gwdatanew_re + 1j*gwdatanew_im + gwdatanew5 = gwdatanew_re5 + 1j*gwdatanew_im5 + + position_in = np.argmax(times_rd >= tshift) + position_end = np.argmax(times_rd >= tend) + times_rd = times_rd[position_in:position_end] + gwdatanew = gwdatanew[position_in:position_end] + gwdatanew5 = gwdatanew5[position_in:position_end] + + return(np.stack((times_rd,gwdatanew)).T,np.stack((times_rd,gwdatanew5)).T) + + +def phase_align(data_1,data_2,t_align=0): + + #timesrd_final = data_1[:,0] + #phas = np.angle(data_1[:,1]) + #phas = np.unwrap(phas) + #phas5 = np.angle(data_2[:,1]) + #phas5 = np.unwrap(phas5) + #position = np.argmax(timesrd_final >= (t_align)) + #dphase = phas5[position]-phas[position] + + #gwdatanew = data_1[:,1]*np.exp(1j*dphase) + + + phas = np.angle(data_1[:,1]) + phas = np.unwrap(phas) + phas5 = np.angle(data_2[:,1]) + phas5 = np.unwrap(phas5) + position = np.argmax(data_1[:,0] >= (0)) + dphase = phas5[position]-phas[position] + gwdatanew = data_1[:,1]*np.exp(1j*dphase) + timesrd_final = data_1[:,0] + + return np.stack((timesrd_final,gwdatanew)).T + +def create_output_files(output_folder,pars,file_type): + sim_num, model, nmax, tshift, npoints = pars + + """ + Generate the output files you want to export the data to. + file_type must be one of this options: [corner_plot,corner_plot_extra,diagnosis,fit,post_samples,sampler_results,log_z] + """ + + if file_type=='corner_plot': + outfile = output_folder+'/Dynesty_'+str(sim_num)+'_'+model+'_nmax_'+str(nmax)+'_tshift_'+str(tshift)+'_'+str(npoints)+'corner_plot.png' + elif file_type=='corner_plot_extra': + outfile = output_folder+'/Dynesty_'+str(sim_num)+'_'+model+'_nmax_'+str(nmax)+'_tshift_'+str(tshift)+'_'+str(npoints)+'corner_plot_extra.png' + elif file_type=='diagnosis': + outfile = output_folder+'/Dynesty_diagnosis'+str(sim_num)+'_'+model+'_nmax_'+str(nmax)+'_tshift_'+str(tshift)+'_'+str(npoints)+'.png' + elif file_type=='fit': + outfile = output_folder+'/Fit_results_'+str(sim_num)+'tshift_'+str(tshift)+'_'+model+'_nmax_'+str(nmax)+'.png' + elif file_type=='post_samples': + outfile = output_folder+'/posterior_samples-'+str(sim_num)+'tshift_'+str(tshift)+'_'+model+'_nmax_'+str(nmax)+'.csv' + elif file_type=='sampler_results': + outfile = output_folder+'/results_'+str(sim_num)+'tshift_'+str(tshift)+'_'+model+'_nmax_'+str(nmax)+'.pkl' + elif file_type=='log_z': + outfile = output_folder+'/summary'+str(sim_num)+'_'+model+'_nmax_'+str(nmax)+'.csv' + elif file_type=='best_vals': + outfile = output_folder+'/best_values_'+str(sim_num)+'_'+model+'_nmax_'+str(nmax)+'.csv' + else: + print ('Something went wrong') + return + + return outfile + +def read_config_file(parser): + # Setup path and output folders + rootpath=parser.get('nr-paths','rootpath') + simulation_path_1 = parser.get('nr-paths','simulation_path_1') + + if parser.get('nr-paths','simulation_path_2'): + simulation_path_2 = parser.get('nr-paths','simulation_path_2') + else: + simulation_path_2 = simulation_path_1 + + metadata_file = parser.get('nr-paths','metadata_json') + simulation_number = parser.get('nr-paths','simulation_number') + simulation_number = np.int(simulation_number) + + output_folder = parser.get('output-folder','output-folder') + if parser.has_option('setup','export'): + export=eval(parser.get('setup','export')) + else: + export=True + + # Setup sampler and output options + overwrite = eval(parser.get('setup','overwrite')) + downfactor = np.int(parser.get('setup','plot_down_factor')) + sampler = parser.get('setup','sampler') + nr_code = parser.get('setup','nr_code') + if parser.has_option('setup','nb_cores'): + nbcores = np.int(parser.get('setup','nb_cores')) + else: + nbcores = 1 + + # time shift , end and align options + tshift=parser.get('time-setup','tshift') + tshift = np.float(tshift) + + tend=parser.get('time-setup','tend') + tend = np.float(tend) + + t_align=parser.get('time-setup','t_align') + t_align = np.float(t_align) + + # n-tones & nlive points + nmax=parser.get('n-tones','nmax') + nmax = np.int(nmax) + + npoints=parser.get('n-live-points','npoints') + npoints = np.int(npoints) + + # setup the RD model + model=parser.get('rd-model','model') + error_str = eval(parser.get('rd-model','error_str')) + fitnoise=eval(parser.get('rd-model','fit_noise')) + if fitnoise: + l_int=1 + index_mass=-3 + index_spin=-2 + # prior_dim = len(priors_min) + else: + index_mass=-2 + index_spin=-1 + l_int=0 + + if error_str: + error_val=np.float(parser.get('rd-model','error_val')) + if error_val==0: + error_type='' + else: + error_type=error_val + else: + error_type='False' + error_val =0 + + if nr_code == 'SXS': + metadata = {} + with open(metadata_file) as file: + metadata = json.load(file) + af = metadata['remnant_dimensionless_spin'][-1] + mf = metadata['remnant_mass'] + else: + mf = parser.get('rd-mock-parameters','mf') + mf = np.float(mf) + af = np.float(parser.get('rd-mock-parameters','af')) + af = np.float(af) + + if model == 'w-q': + tau_var_str='q' + else: + tau_var_str='tau' + + if nr_code == 'Mock-data': + nm_mock = int(parser.get('rd-mock-parameters','nm_mock')) + else: + nm_mock = None + + res = simulation_path_1,simulation_path_2, metadata_file , simulation_number, output_folder, export, overwrite, sampler,nr_code, nbcores,tshift,tend,t_align, nmax , npoints, model, error_str, fitnoise, l_int, index_mass,index_spin, error_type, error_val, af, mf,tau_var_str,nm_mock + return res \ No newline at end of file diff --git a/code_new/RD_Dynesty_Fits/build/lib/RD_Dynesty_Fits/RD-Dynesty-Fits.py b/code_new/RD_Dynesty_Fits/build/lib/RD_Dynesty_Fits/RD-Dynesty-Fits.py new file mode 100644 index 0000000000000000000000000000000000000000..a8d13aac0567fe30ada2a645e23ee07072da0079 --- /dev/null +++ b/code_new/RD_Dynesty_Fits/build/lib/RD_Dynesty_Fits/RD-Dynesty-Fits.py @@ -0,0 +1,390 @@ +#!/usr/bin/env python +# coding: utf-8 + +# In[38]: + + +"""Generate ringdown templates in the time and perform parameter estimation on them. +""" + + +# In[1]: + + +#Import relevant modules, import data and all that +import time +import numpy as np +import corner +import matplotlib.pyplot as plt +from matplotlib.ticker import MaxNLocator +from matplotlib import rc +from configparser import ConfigParser +plt.rcParams.update({'font.size': 16.5}) + +from multiprocessing import Pool +import random +import dynesty +from dynesty import plotting as dyplot +from dynesty.utils import resample_equal +from dynesty import utils as dyfunc +import os +import argparse +import scipy.optimize as optimization +from scipy.optimize import minimize +import rdown as rd +import rdown_pe as rd_pe +import rdown_utilities as rd_ut +import read_data as rdata + + +# In[2]: + + +## Loading and running data tested with NR data +## Loading and running data tested with Mock data + + +# In[3]: + + +# Cell that calls the arguments from your 'config.ini' file. +try: + parser = argparse.ArgumentParser(description="Simple argument parser") + parser.add_argument("-c", action="store", dest="config_file") + result = parser.parse_args() + config_file=result.config_file + parser = ConfigParser() + parser.read(config_file) + parser.sections() +except SystemExit: + parser = ConfigParser() + parser.read('./run_0_mock/config_n0_to_1_mock.ini') + parser.sections() + pass + + +# In[4]: + + +# Load variables from config file +(simulation_path_1,simulation_path_2, metadata_file , simulation_number, output_folder, + export, overwrite, sampler,nr_code, nbcores,tshift,tend,t_align, + nmax , npoints, model, error_str, fitnoise, l_int, index_mass,index_spin, +error_type, error_val, af, mf,tau_var_str,nm_mock)=rdata.read_config_file(parser) + + +# In[5]: + + +# Show configuration options +dim = nmax+1 +ndim = 4*dim +numbins = 32 #corner plot parameter - how many bins you want + +print('model:',model) +print('nmax:',nmax) +print('nm_mock:',nm_mock) +print('tshift:',tshift) +print('error:', error_str) +print('error value:',error_val) +print('export:',export) +print('nr code:',nr_code) +print('fit noise:',fitnoise) + + +# In[6]: + + +# Create output directories +if not os.path.exists(output_folder): + os.mkdir(output_folder) + print("Directory " , output_folder , " Created ") + +if nr_code == 'Mock-data': + nm_mock_str = 'rec_with'+parser.get('rd-mock-parameters','nm_mock')+'_' +else: + nm_mock_str='' + +if error_str: + output_folder_1=(output_folder+'/'+model+'-nmax'+str(nmax)+'_'+nm_mock_str+str(error_str)+'_'+str(error_type)+'_fitnoise_'+str(fitnoise)) +else: + output_folder_1=output_folder+'/'+model+'-nmax'+str(nmax)+'_'+nm_mock_str+str(error_str)+'_'+'fitnoise_'+str(fitnoise) + +if not os.path.exists(output_folder_1): + os.mkdir(output_folder_1) + print("Directory " , output_folder_1 , " Created ") + + +# In[7]: + + +# Define output files +pars = [simulation_number,model,nmax,tshift,npoints] +corner_plot = rdata.create_output_files(output_folder_1,pars,'corner_plot') +corner_plot_extra = rdata.create_output_files(output_folder_1,pars,'corner_plot_extra') +diagnosis_plot = rdata.create_output_files(output_folder_1,pars,'diagnosis') +fit_plot = rdata.create_output_files(output_folder_1,pars,'fit') +samples_file = rdata.create_output_files(output_folder_1,pars,'post_samples') +results_file = rdata.create_output_files(output_folder_1,pars,'sampler_results') +sumary_data = rdata.create_output_files(output_folder_1,pars,'log_z') +best_data = rdata.create_output_files(output_folder_1,pars,'best_vals') + +files = [corner_plot,corner_plot_extra,diagnosis_plot,fit_plot,samples_file,results_file,sumary_data,best_data] + + +# In[8]: + + +# Remove old files if overwrite = True +if overwrite: + rd_ut.rm_files(files) + + +# In[46]: + + +#Load NR data, align in time and resize. Plot real part and amplitude. Finally compute the mismatch and the snr estimate +data = rdata.read_data(nr_code,simulation_path_1,RD=True,tshift=tshift,tend = tend,metadata_file=metadata_file,parser=parser) +data_l = rdata.read_data(nr_code,simulation_path_2,RD=True,tshift=tshift,tend = tend,metadata_file=metadata_file,parser=parser) +data_r, data_lr = rdata.nr_resize(data,data_l,tshift=tshift,tend=tend) +times_rd = data_r[:,0] + +plt.figure(figsize = (12, 8)) +plt.plot(times_rd, data_r[:,1].real, "r", alpha=0.3, lw=3, label=r'$Lev6$: real') +plt.plot(times_rd, np.sqrt((data_r[:,1].real)**2+(data_r[:,1].imag)**2), "r", alpha=0.3, lw=3, label=r'$Lev5\,amp$') +plt.plot(times_rd, data_lr[:,1].real, "b", alpha=0.3, lw=3, label=r'$Lev5: real$') +plt.plot(times_rd, np.sqrt((data_lr[:,1].real)**2+(data_lr[:,1].imag)**2), "b", alpha=0.3, lw=3, label=r'$Lev5\,amp$') +if error_str and error_val==0: + error = np.sqrt(data_r[:,1]*data_r[:,1]-2*data_r[:,1]*data_lr[:,1]+data_lr[:,1]*data_lr[:,1]) + error_est=np.sqrt(error.imag**2+error.real**2) + plt.plot(times_rd, error_est, "g", alpha=0.3, lw=2, label='error') +plt.legend() + +mismatch=1-rd_ut.EasyMatchT(times_rd,data_r[:,1],data_lr[:,1],tshift,tend) +error=np.sqrt(2*mismatch) +print('error estimate:',error) +print('mismatch:', mismatch) +print('snr:', rd_ut.EasySNRT(times_rd,data_r[:,1],data_lr[:,1],tshift,tend)/error**2) + + +# In[47]: + + +# Phase alignement +if parser.has_option('rd-model','phase_alignment'): + phase_alignment=eval(parser.get('rd-model','phase_alignment')) +else: + phase_alignment=False + +if phase_alignment: + datar_al = rdata.phase_align(data_r,data_lr) + gwdatanew5 = data_lr[:,1] + gwdatanew = datar_al[:,1] + timesrd_final = datar_al[:,0] + mismatch=1-rd_ut.EasyMatchT(timesrd_final,gwdatanew,gwdatanew5,tshift,tend) + error=np.sqrt(2*mismatch) + print('error estimate:',error) + print('mismatch:', mismatch) + print('snr:', rd_ut.EasySNRT(timesrd_final,gwdatanew,gwdatanew5,tshift,tend)/error) + if error_str: + error = np.sqrt(gwdatanew*gwdatanew-2*gwdatanew*gwdatanew5+gwdatanew5*gwdatanew5) + error_est=np.sqrt(error.imag**2+error.real**2) + else : + error = 1 +else: + datar_al = data_r + timesrd_final = datar_al[:,0] + +#Test the new interpolated data +if error_str and error_val==0: + plt.figure(figsize = (12, 8)) + plt.plot(timesrd_final, datar_al[:,1].real, "r", alpha=0.3, lw=2, label='Original') + plt.plot(timesrd_final, data_lr[:,1].real, "b", alpha=0.3, lw=2, label='Aligned') + plt.plot(timesrd_final, error_est, "b", alpha=0.3, lw=2, label='error') + plt.legend() + + +# In[48]: + + +# Define your noise depending on the noise configuration. Load priors and setup the likelihood with rd_pe.Ringdown_PE. +if error_str and error_val==0: + error_final = error_est + norm_factor = 100*len(error_final)/2*np.log(2*np.pi) +elif error_str and error_val!=0: + datar_al[:,1]+=random.uniform(0, error_val) + datar_al[:,1]+=1j*random.uniform(0, error_val) + error_tsh = error_val + error_final=(error_tsh.real**2+error_tsh.imag**2) + norm_factor = 0 +else: + error_tsh=1 + error_final=(error_tsh.real**2+error_tsh.imag**2) + norm_factor = 0 + +priors = rd_pe.load_priors(model,parser,nmax,fitnoise=fitnoise) +rdown=rd.Ringdown_Spectrum(mf,af,2,2,n=nmax,s=-2,time=timesrd_final) +rdown_pe = rd_pe.Ringdown_PE(rdown,datar_al,dim,priors,errors2=error_final,norm_factor=norm_factor,model=model,l_int=l_int) + + +# In[49]: + + +# Get a first estimate by trying to fit the data. +nll = lambda *args: -rdown_pe.log_likelihood(*args) +if model == 'w-tau-fixed-m-af': + if fitnoise: + initial = np.concatenate((np.ones(2*dim),[0.8,0.9,1])) + soln = minimize(nll, initial,bounds=priors) + vars_ml=soln.x + else: + initial = np.concatenate((np.ones(2*dim),[0.8,0.9])) + soln = minimize(nll, initial,bounds=priors) + vars_ml=soln.x +elif model == 'w-tau-fixed': + if fitnoise: + initial = np.concatenate((np.ones(2*dim),[0.2])) + soln = minimize(nll, initial,bounds=priors) + vars_ml=soln.x + else: + initial = np.ones(2*dim) + soln = minimize(nll, initial,bounds=priors) + vars_ml=soln.x +else: + if fitnoise: + initial = np.concatenate((np.ones(ndim),[1])) + soln = minimize(nll, initial,bounds=priors) + vars_ml=soln.x + else: + initial = np.ones(ndim) + soln = minimize(nll, initial,bounds=priors) + vars_ml=soln.x +print("best fit pars from fit: ",vars_ml) + + +# In[50]: + + +mypool = Pool(nbcores) +mypool.size = nbcores + +start = time.process_time() +f2=dynesty.NestedSampler(rdown_pe.log_likelihood,rdown_pe.prior_transform, len(priors), nlive=npoints,sample=sampler,pool=mypool) +if parser.has_option('setup','dlogz'): + dlogz=np.float(parser.get('setup','dlogz')) + f2.run_nested(dlogz=dlogz,print_progress=False) +else: + f2.run_nested(print_progress=False) + +print(time.process_time() - start) + + +# In[52]: + + +res = f2.results +res.samples_u.shape +res.summary() +samps=f2.results.samples +postsamps = rd_ut.posterior_samples(f2) +samps_tr=np.transpose(samps) +half_points=int(round((len(samps_tr[0])/1.25))) +evidence = res.logz[-1] +evidence_error = res.logzerr[-1] +if export: + rd_ut.save_object(res, results_file) + + +# In[53]: + + +pars = nmax,model,samps_tr, half_points +npamps = rd_ut.get_best_amps(pars,parser=parser,nr_code=nr_code) + + +# In[54]: + + +if export: + pars = simulation_number, nmax, tshift, evidence, evidence_error + rd_ut.export_logz_files(sumary_data,pars) + + +# In[55]: + + +labels = rd_ut.define_labels(dim,model,fitnoise) +if export: + pars = tshift, len(priors), labels + rd_ut.export_bestvals_files(best_data,postsamps,pars) + + +# In[56]: + + +w, tau = rdown.QNM_spectrum() +pars = w, tau, mf, af, npamps +truths = rd_ut.get_truths(model,pars,fitnoise) + + +# In[57]: + + +fg=corner.corner(postsamps,quantiles=[0.05,0.5,0.95],show_titles=True,max_n_ticks = 4,bins=50,truths=truths,labels=labels,truth_color='red') +plt.show() +if export: + fg.savefig(corner_plot, format = 'png', bbox_inches = 'tight') + + +# In[58]: + + +from importlib import reload +reload(rd_ut) +if model == 'w-tau-fixed-m-af' and export == True: + truths=np.concatenate((w,tau)) + labels_mf = np.concatenate((w_lab,tau_lab)) + new_samples = rd_ut.convert_m_af_2_w_tau_post(res,fitnoise=False) + figure = corner.corner(new_samples,truths=truths,quantiles=[0.05,0.95],labels=labels_mf,smooth=True,color='b',truth_color='r',show_titles=True) + figure.savefig(corner_plot_extra, format = 'png', bbox_inches = 'tight') + + +# In[151]: + + +#lnz_truth = ndim * -np.log(2 * 10.) # analytic evidence solution +fig, axes = dyplot.runplot(res) +fig.tight_layout() +if export: + fig.savefig(diagnosis_plot, format = 'png', dpi = 384, bbox_inches = 'tight') + + +# In[166]: + + +if export: + dict = {'w-tau':rdown.rd_model_wtau , 'w-q': rdown.rd_model_wq, 'w-tau-fixed':rdown.rd_model_wtau_fixed,'w-tau-fixed-m-af': rdown.rd_model_wtau_m_af} + figband = plt.figure(figsize = (12, 9)) + plt.plot(datar_al[:,0].real,datar_al[:,1].real, "green", alpha=0.9, lw=3, label=r'$res_{240}$') + onesig_bounds = np.array([np.percentile(postsamps[:, i], [5, 95]) for i in range(len(postsamps[0]))]).T + samples_1sigma = filter(lambda sample: np.all(onesig_bounds[0] <= sample) and np.all(sample <= onesig_bounds[1]), postsamps) + samples_1sigma_down = list(samples_1sigma)[::downfactor] + for sample in samples_1sigma_down: + plt.plot(datar_al[:,0].real, dict[model](sample).real, "r-", alpha=0.1, lw=1) + plt.title(r'Comparison of the MC fit data and the $1-\sigma$ error band') + plt.legend() + plt.xlabel('t') + plt.ylabel('h') + plt.show() + figband.savefig(fit_plot) + + +# In[162]: + + +if export: + with open(samples_file,'w') as file: + writer = csv.writer(file) + writer.writerow(labels) + writer.writerows(samps[::downfactor]) + diff --git a/code_new/RD_Dynesty_Fits/build/lib/RD_Dynesty_Fits/RD_Dynesty_Fits.py b/code_new/RD_Dynesty_Fits/build/lib/RD_Dynesty_Fits/RD_Dynesty_Fits.py new file mode 100644 index 0000000000000000000000000000000000000000..a8d13aac0567fe30ada2a645e23ee07072da0079 --- /dev/null +++ b/code_new/RD_Dynesty_Fits/build/lib/RD_Dynesty_Fits/RD_Dynesty_Fits.py @@ -0,0 +1,390 @@ +#!/usr/bin/env python +# coding: utf-8 + +# In[38]: + + +"""Generate ringdown templates in the time and perform parameter estimation on them. +""" + + +# In[1]: + + +#Import relevant modules, import data and all that +import time +import numpy as np +import corner +import matplotlib.pyplot as plt +from matplotlib.ticker import MaxNLocator +from matplotlib import rc +from configparser import ConfigParser +plt.rcParams.update({'font.size': 16.5}) + +from multiprocessing import Pool +import random +import dynesty +from dynesty import plotting as dyplot +from dynesty.utils import resample_equal +from dynesty import utils as dyfunc +import os +import argparse +import scipy.optimize as optimization +from scipy.optimize import minimize +import rdown as rd +import rdown_pe as rd_pe +import rdown_utilities as rd_ut +import read_data as rdata + + +# In[2]: + + +## Loading and running data tested with NR data +## Loading and running data tested with Mock data + + +# In[3]: + + +# Cell that calls the arguments from your 'config.ini' file. +try: + parser = argparse.ArgumentParser(description="Simple argument parser") + parser.add_argument("-c", action="store", dest="config_file") + result = parser.parse_args() + config_file=result.config_file + parser = ConfigParser() + parser.read(config_file) + parser.sections() +except SystemExit: + parser = ConfigParser() + parser.read('./run_0_mock/config_n0_to_1_mock.ini') + parser.sections() + pass + + +# In[4]: + + +# Load variables from config file +(simulation_path_1,simulation_path_2, metadata_file , simulation_number, output_folder, + export, overwrite, sampler,nr_code, nbcores,tshift,tend,t_align, + nmax , npoints, model, error_str, fitnoise, l_int, index_mass,index_spin, +error_type, error_val, af, mf,tau_var_str,nm_mock)=rdata.read_config_file(parser) + + +# In[5]: + + +# Show configuration options +dim = nmax+1 +ndim = 4*dim +numbins = 32 #corner plot parameter - how many bins you want + +print('model:',model) +print('nmax:',nmax) +print('nm_mock:',nm_mock) +print('tshift:',tshift) +print('error:', error_str) +print('error value:',error_val) +print('export:',export) +print('nr code:',nr_code) +print('fit noise:',fitnoise) + + +# In[6]: + + +# Create output directories +if not os.path.exists(output_folder): + os.mkdir(output_folder) + print("Directory " , output_folder , " Created ") + +if nr_code == 'Mock-data': + nm_mock_str = 'rec_with'+parser.get('rd-mock-parameters','nm_mock')+'_' +else: + nm_mock_str='' + +if error_str: + output_folder_1=(output_folder+'/'+model+'-nmax'+str(nmax)+'_'+nm_mock_str+str(error_str)+'_'+str(error_type)+'_fitnoise_'+str(fitnoise)) +else: + output_folder_1=output_folder+'/'+model+'-nmax'+str(nmax)+'_'+nm_mock_str+str(error_str)+'_'+'fitnoise_'+str(fitnoise) + +if not os.path.exists(output_folder_1): + os.mkdir(output_folder_1) + print("Directory " , output_folder_1 , " Created ") + + +# In[7]: + + +# Define output files +pars = [simulation_number,model,nmax,tshift,npoints] +corner_plot = rdata.create_output_files(output_folder_1,pars,'corner_plot') +corner_plot_extra = rdata.create_output_files(output_folder_1,pars,'corner_plot_extra') +diagnosis_plot = rdata.create_output_files(output_folder_1,pars,'diagnosis') +fit_plot = rdata.create_output_files(output_folder_1,pars,'fit') +samples_file = rdata.create_output_files(output_folder_1,pars,'post_samples') +results_file = rdata.create_output_files(output_folder_1,pars,'sampler_results') +sumary_data = rdata.create_output_files(output_folder_1,pars,'log_z') +best_data = rdata.create_output_files(output_folder_1,pars,'best_vals') + +files = [corner_plot,corner_plot_extra,diagnosis_plot,fit_plot,samples_file,results_file,sumary_data,best_data] + + +# In[8]: + + +# Remove old files if overwrite = True +if overwrite: + rd_ut.rm_files(files) + + +# In[46]: + + +#Load NR data, align in time and resize. Plot real part and amplitude. Finally compute the mismatch and the snr estimate +data = rdata.read_data(nr_code,simulation_path_1,RD=True,tshift=tshift,tend = tend,metadata_file=metadata_file,parser=parser) +data_l = rdata.read_data(nr_code,simulation_path_2,RD=True,tshift=tshift,tend = tend,metadata_file=metadata_file,parser=parser) +data_r, data_lr = rdata.nr_resize(data,data_l,tshift=tshift,tend=tend) +times_rd = data_r[:,0] + +plt.figure(figsize = (12, 8)) +plt.plot(times_rd, data_r[:,1].real, "r", alpha=0.3, lw=3, label=r'$Lev6$: real') +plt.plot(times_rd, np.sqrt((data_r[:,1].real)**2+(data_r[:,1].imag)**2), "r", alpha=0.3, lw=3, label=r'$Lev5\,amp$') +plt.plot(times_rd, data_lr[:,1].real, "b", alpha=0.3, lw=3, label=r'$Lev5: real$') +plt.plot(times_rd, np.sqrt((data_lr[:,1].real)**2+(data_lr[:,1].imag)**2), "b", alpha=0.3, lw=3, label=r'$Lev5\,amp$') +if error_str and error_val==0: + error = np.sqrt(data_r[:,1]*data_r[:,1]-2*data_r[:,1]*data_lr[:,1]+data_lr[:,1]*data_lr[:,1]) + error_est=np.sqrt(error.imag**2+error.real**2) + plt.plot(times_rd, error_est, "g", alpha=0.3, lw=2, label='error') +plt.legend() + +mismatch=1-rd_ut.EasyMatchT(times_rd,data_r[:,1],data_lr[:,1],tshift,tend) +error=np.sqrt(2*mismatch) +print('error estimate:',error) +print('mismatch:', mismatch) +print('snr:', rd_ut.EasySNRT(times_rd,data_r[:,1],data_lr[:,1],tshift,tend)/error**2) + + +# In[47]: + + +# Phase alignement +if parser.has_option('rd-model','phase_alignment'): + phase_alignment=eval(parser.get('rd-model','phase_alignment')) +else: + phase_alignment=False + +if phase_alignment: + datar_al = rdata.phase_align(data_r,data_lr) + gwdatanew5 = data_lr[:,1] + gwdatanew = datar_al[:,1] + timesrd_final = datar_al[:,0] + mismatch=1-rd_ut.EasyMatchT(timesrd_final,gwdatanew,gwdatanew5,tshift,tend) + error=np.sqrt(2*mismatch) + print('error estimate:',error) + print('mismatch:', mismatch) + print('snr:', rd_ut.EasySNRT(timesrd_final,gwdatanew,gwdatanew5,tshift,tend)/error) + if error_str: + error = np.sqrt(gwdatanew*gwdatanew-2*gwdatanew*gwdatanew5+gwdatanew5*gwdatanew5) + error_est=np.sqrt(error.imag**2+error.real**2) + else : + error = 1 +else: + datar_al = data_r + timesrd_final = datar_al[:,0] + +#Test the new interpolated data +if error_str and error_val==0: + plt.figure(figsize = (12, 8)) + plt.plot(timesrd_final, datar_al[:,1].real, "r", alpha=0.3, lw=2, label='Original') + plt.plot(timesrd_final, data_lr[:,1].real, "b", alpha=0.3, lw=2, label='Aligned') + plt.plot(timesrd_final, error_est, "b", alpha=0.3, lw=2, label='error') + plt.legend() + + +# In[48]: + + +# Define your noise depending on the noise configuration. Load priors and setup the likelihood with rd_pe.Ringdown_PE. +if error_str and error_val==0: + error_final = error_est + norm_factor = 100*len(error_final)/2*np.log(2*np.pi) +elif error_str and error_val!=0: + datar_al[:,1]+=random.uniform(0, error_val) + datar_al[:,1]+=1j*random.uniform(0, error_val) + error_tsh = error_val + error_final=(error_tsh.real**2+error_tsh.imag**2) + norm_factor = 0 +else: + error_tsh=1 + error_final=(error_tsh.real**2+error_tsh.imag**2) + norm_factor = 0 + +priors = rd_pe.load_priors(model,parser,nmax,fitnoise=fitnoise) +rdown=rd.Ringdown_Spectrum(mf,af,2,2,n=nmax,s=-2,time=timesrd_final) +rdown_pe = rd_pe.Ringdown_PE(rdown,datar_al,dim,priors,errors2=error_final,norm_factor=norm_factor,model=model,l_int=l_int) + + +# In[49]: + + +# Get a first estimate by trying to fit the data. +nll = lambda *args: -rdown_pe.log_likelihood(*args) +if model == 'w-tau-fixed-m-af': + if fitnoise: + initial = np.concatenate((np.ones(2*dim),[0.8,0.9,1])) + soln = minimize(nll, initial,bounds=priors) + vars_ml=soln.x + else: + initial = np.concatenate((np.ones(2*dim),[0.8,0.9])) + soln = minimize(nll, initial,bounds=priors) + vars_ml=soln.x +elif model == 'w-tau-fixed': + if fitnoise: + initial = np.concatenate((np.ones(2*dim),[0.2])) + soln = minimize(nll, initial,bounds=priors) + vars_ml=soln.x + else: + initial = np.ones(2*dim) + soln = minimize(nll, initial,bounds=priors) + vars_ml=soln.x +else: + if fitnoise: + initial = np.concatenate((np.ones(ndim),[1])) + soln = minimize(nll, initial,bounds=priors) + vars_ml=soln.x + else: + initial = np.ones(ndim) + soln = minimize(nll, initial,bounds=priors) + vars_ml=soln.x +print("best fit pars from fit: ",vars_ml) + + +# In[50]: + + +mypool = Pool(nbcores) +mypool.size = nbcores + +start = time.process_time() +f2=dynesty.NestedSampler(rdown_pe.log_likelihood,rdown_pe.prior_transform, len(priors), nlive=npoints,sample=sampler,pool=mypool) +if parser.has_option('setup','dlogz'): + dlogz=np.float(parser.get('setup','dlogz')) + f2.run_nested(dlogz=dlogz,print_progress=False) +else: + f2.run_nested(print_progress=False) + +print(time.process_time() - start) + + +# In[52]: + + +res = f2.results +res.samples_u.shape +res.summary() +samps=f2.results.samples +postsamps = rd_ut.posterior_samples(f2) +samps_tr=np.transpose(samps) +half_points=int(round((len(samps_tr[0])/1.25))) +evidence = res.logz[-1] +evidence_error = res.logzerr[-1] +if export: + rd_ut.save_object(res, results_file) + + +# In[53]: + + +pars = nmax,model,samps_tr, half_points +npamps = rd_ut.get_best_amps(pars,parser=parser,nr_code=nr_code) + + +# In[54]: + + +if export: + pars = simulation_number, nmax, tshift, evidence, evidence_error + rd_ut.export_logz_files(sumary_data,pars) + + +# In[55]: + + +labels = rd_ut.define_labels(dim,model,fitnoise) +if export: + pars = tshift, len(priors), labels + rd_ut.export_bestvals_files(best_data,postsamps,pars) + + +# In[56]: + + +w, tau = rdown.QNM_spectrum() +pars = w, tau, mf, af, npamps +truths = rd_ut.get_truths(model,pars,fitnoise) + + +# In[57]: + + +fg=corner.corner(postsamps,quantiles=[0.05,0.5,0.95],show_titles=True,max_n_ticks = 4,bins=50,truths=truths,labels=labels,truth_color='red') +plt.show() +if export: + fg.savefig(corner_plot, format = 'png', bbox_inches = 'tight') + + +# In[58]: + + +from importlib import reload +reload(rd_ut) +if model == 'w-tau-fixed-m-af' and export == True: + truths=np.concatenate((w,tau)) + labels_mf = np.concatenate((w_lab,tau_lab)) + new_samples = rd_ut.convert_m_af_2_w_tau_post(res,fitnoise=False) + figure = corner.corner(new_samples,truths=truths,quantiles=[0.05,0.95],labels=labels_mf,smooth=True,color='b',truth_color='r',show_titles=True) + figure.savefig(corner_plot_extra, format = 'png', bbox_inches = 'tight') + + +# In[151]: + + +#lnz_truth = ndim * -np.log(2 * 10.) # analytic evidence solution +fig, axes = dyplot.runplot(res) +fig.tight_layout() +if export: + fig.savefig(diagnosis_plot, format = 'png', dpi = 384, bbox_inches = 'tight') + + +# In[166]: + + +if export: + dict = {'w-tau':rdown.rd_model_wtau , 'w-q': rdown.rd_model_wq, 'w-tau-fixed':rdown.rd_model_wtau_fixed,'w-tau-fixed-m-af': rdown.rd_model_wtau_m_af} + figband = plt.figure(figsize = (12, 9)) + plt.plot(datar_al[:,0].real,datar_al[:,1].real, "green", alpha=0.9, lw=3, label=r'$res_{240}$') + onesig_bounds = np.array([np.percentile(postsamps[:, i], [5, 95]) for i in range(len(postsamps[0]))]).T + samples_1sigma = filter(lambda sample: np.all(onesig_bounds[0] <= sample) and np.all(sample <= onesig_bounds[1]), postsamps) + samples_1sigma_down = list(samples_1sigma)[::downfactor] + for sample in samples_1sigma_down: + plt.plot(datar_al[:,0].real, dict[model](sample).real, "r-", alpha=0.1, lw=1) + plt.title(r'Comparison of the MC fit data and the $1-\sigma$ error band') + plt.legend() + plt.xlabel('t') + plt.ylabel('h') + plt.show() + figband.savefig(fit_plot) + + +# In[162]: + + +if export: + with open(samples_file,'w') as file: + writer = csv.writer(file) + writer.writerow(labels) + writer.writerows(samps[::downfactor]) + diff --git a/code_new/RD_Dynesty_Fits/build/lib/RD_Dynesty_Fits/RD_Fits.py b/code_new/RD_Dynesty_Fits/build/lib/RD_Dynesty_Fits/RD_Fits.py new file mode 100644 index 0000000000000000000000000000000000000000..a8d13aac0567fe30ada2a645e23ee07072da0079 --- /dev/null +++ b/code_new/RD_Dynesty_Fits/build/lib/RD_Dynesty_Fits/RD_Fits.py @@ -0,0 +1,390 @@ +#!/usr/bin/env python +# coding: utf-8 + +# In[38]: + + +"""Generate ringdown templates in the time and perform parameter estimation on them. +""" + + +# In[1]: + + +#Import relevant modules, import data and all that +import time +import numpy as np +import corner +import matplotlib.pyplot as plt +from matplotlib.ticker import MaxNLocator +from matplotlib import rc +from configparser import ConfigParser +plt.rcParams.update({'font.size': 16.5}) + +from multiprocessing import Pool +import random +import dynesty +from dynesty import plotting as dyplot +from dynesty.utils import resample_equal +from dynesty import utils as dyfunc +import os +import argparse +import scipy.optimize as optimization +from scipy.optimize import minimize +import rdown as rd +import rdown_pe as rd_pe +import rdown_utilities as rd_ut +import read_data as rdata + + +# In[2]: + + +## Loading and running data tested with NR data +## Loading and running data tested with Mock data + + +# In[3]: + + +# Cell that calls the arguments from your 'config.ini' file. +try: + parser = argparse.ArgumentParser(description="Simple argument parser") + parser.add_argument("-c", action="store", dest="config_file") + result = parser.parse_args() + config_file=result.config_file + parser = ConfigParser() + parser.read(config_file) + parser.sections() +except SystemExit: + parser = ConfigParser() + parser.read('./run_0_mock/config_n0_to_1_mock.ini') + parser.sections() + pass + + +# In[4]: + + +# Load variables from config file +(simulation_path_1,simulation_path_2, metadata_file , simulation_number, output_folder, + export, overwrite, sampler,nr_code, nbcores,tshift,tend,t_align, + nmax , npoints, model, error_str, fitnoise, l_int, index_mass,index_spin, +error_type, error_val, af, mf,tau_var_str,nm_mock)=rdata.read_config_file(parser) + + +# In[5]: + + +# Show configuration options +dim = nmax+1 +ndim = 4*dim +numbins = 32 #corner plot parameter - how many bins you want + +print('model:',model) +print('nmax:',nmax) +print('nm_mock:',nm_mock) +print('tshift:',tshift) +print('error:', error_str) +print('error value:',error_val) +print('export:',export) +print('nr code:',nr_code) +print('fit noise:',fitnoise) + + +# In[6]: + + +# Create output directories +if not os.path.exists(output_folder): + os.mkdir(output_folder) + print("Directory " , output_folder , " Created ") + +if nr_code == 'Mock-data': + nm_mock_str = 'rec_with'+parser.get('rd-mock-parameters','nm_mock')+'_' +else: + nm_mock_str='' + +if error_str: + output_folder_1=(output_folder+'/'+model+'-nmax'+str(nmax)+'_'+nm_mock_str+str(error_str)+'_'+str(error_type)+'_fitnoise_'+str(fitnoise)) +else: + output_folder_1=output_folder+'/'+model+'-nmax'+str(nmax)+'_'+nm_mock_str+str(error_str)+'_'+'fitnoise_'+str(fitnoise) + +if not os.path.exists(output_folder_1): + os.mkdir(output_folder_1) + print("Directory " , output_folder_1 , " Created ") + + +# In[7]: + + +# Define output files +pars = [simulation_number,model,nmax,tshift,npoints] +corner_plot = rdata.create_output_files(output_folder_1,pars,'corner_plot') +corner_plot_extra = rdata.create_output_files(output_folder_1,pars,'corner_plot_extra') +diagnosis_plot = rdata.create_output_files(output_folder_1,pars,'diagnosis') +fit_plot = rdata.create_output_files(output_folder_1,pars,'fit') +samples_file = rdata.create_output_files(output_folder_1,pars,'post_samples') +results_file = rdata.create_output_files(output_folder_1,pars,'sampler_results') +sumary_data = rdata.create_output_files(output_folder_1,pars,'log_z') +best_data = rdata.create_output_files(output_folder_1,pars,'best_vals') + +files = [corner_plot,corner_plot_extra,diagnosis_plot,fit_plot,samples_file,results_file,sumary_data,best_data] + + +# In[8]: + + +# Remove old files if overwrite = True +if overwrite: + rd_ut.rm_files(files) + + +# In[46]: + + +#Load NR data, align in time and resize. Plot real part and amplitude. Finally compute the mismatch and the snr estimate +data = rdata.read_data(nr_code,simulation_path_1,RD=True,tshift=tshift,tend = tend,metadata_file=metadata_file,parser=parser) +data_l = rdata.read_data(nr_code,simulation_path_2,RD=True,tshift=tshift,tend = tend,metadata_file=metadata_file,parser=parser) +data_r, data_lr = rdata.nr_resize(data,data_l,tshift=tshift,tend=tend) +times_rd = data_r[:,0] + +plt.figure(figsize = (12, 8)) +plt.plot(times_rd, data_r[:,1].real, "r", alpha=0.3, lw=3, label=r'$Lev6$: real') +plt.plot(times_rd, np.sqrt((data_r[:,1].real)**2+(data_r[:,1].imag)**2), "r", alpha=0.3, lw=3, label=r'$Lev5\,amp$') +plt.plot(times_rd, data_lr[:,1].real, "b", alpha=0.3, lw=3, label=r'$Lev5: real$') +plt.plot(times_rd, np.sqrt((data_lr[:,1].real)**2+(data_lr[:,1].imag)**2), "b", alpha=0.3, lw=3, label=r'$Lev5\,amp$') +if error_str and error_val==0: + error = np.sqrt(data_r[:,1]*data_r[:,1]-2*data_r[:,1]*data_lr[:,1]+data_lr[:,1]*data_lr[:,1]) + error_est=np.sqrt(error.imag**2+error.real**2) + plt.plot(times_rd, error_est, "g", alpha=0.3, lw=2, label='error') +plt.legend() + +mismatch=1-rd_ut.EasyMatchT(times_rd,data_r[:,1],data_lr[:,1],tshift,tend) +error=np.sqrt(2*mismatch) +print('error estimate:',error) +print('mismatch:', mismatch) +print('snr:', rd_ut.EasySNRT(times_rd,data_r[:,1],data_lr[:,1],tshift,tend)/error**2) + + +# In[47]: + + +# Phase alignement +if parser.has_option('rd-model','phase_alignment'): + phase_alignment=eval(parser.get('rd-model','phase_alignment')) +else: + phase_alignment=False + +if phase_alignment: + datar_al = rdata.phase_align(data_r,data_lr) + gwdatanew5 = data_lr[:,1] + gwdatanew = datar_al[:,1] + timesrd_final = datar_al[:,0] + mismatch=1-rd_ut.EasyMatchT(timesrd_final,gwdatanew,gwdatanew5,tshift,tend) + error=np.sqrt(2*mismatch) + print('error estimate:',error) + print('mismatch:', mismatch) + print('snr:', rd_ut.EasySNRT(timesrd_final,gwdatanew,gwdatanew5,tshift,tend)/error) + if error_str: + error = np.sqrt(gwdatanew*gwdatanew-2*gwdatanew*gwdatanew5+gwdatanew5*gwdatanew5) + error_est=np.sqrt(error.imag**2+error.real**2) + else : + error = 1 +else: + datar_al = data_r + timesrd_final = datar_al[:,0] + +#Test the new interpolated data +if error_str and error_val==0: + plt.figure(figsize = (12, 8)) + plt.plot(timesrd_final, datar_al[:,1].real, "r", alpha=0.3, lw=2, label='Original') + plt.plot(timesrd_final, data_lr[:,1].real, "b", alpha=0.3, lw=2, label='Aligned') + plt.plot(timesrd_final, error_est, "b", alpha=0.3, lw=2, label='error') + plt.legend() + + +# In[48]: + + +# Define your noise depending on the noise configuration. Load priors and setup the likelihood with rd_pe.Ringdown_PE. +if error_str and error_val==0: + error_final = error_est + norm_factor = 100*len(error_final)/2*np.log(2*np.pi) +elif error_str and error_val!=0: + datar_al[:,1]+=random.uniform(0, error_val) + datar_al[:,1]+=1j*random.uniform(0, error_val) + error_tsh = error_val + error_final=(error_tsh.real**2+error_tsh.imag**2) + norm_factor = 0 +else: + error_tsh=1 + error_final=(error_tsh.real**2+error_tsh.imag**2) + norm_factor = 0 + +priors = rd_pe.load_priors(model,parser,nmax,fitnoise=fitnoise) +rdown=rd.Ringdown_Spectrum(mf,af,2,2,n=nmax,s=-2,time=timesrd_final) +rdown_pe = rd_pe.Ringdown_PE(rdown,datar_al,dim,priors,errors2=error_final,norm_factor=norm_factor,model=model,l_int=l_int) + + +# In[49]: + + +# Get a first estimate by trying to fit the data. +nll = lambda *args: -rdown_pe.log_likelihood(*args) +if model == 'w-tau-fixed-m-af': + if fitnoise: + initial = np.concatenate((np.ones(2*dim),[0.8,0.9,1])) + soln = minimize(nll, initial,bounds=priors) + vars_ml=soln.x + else: + initial = np.concatenate((np.ones(2*dim),[0.8,0.9])) + soln = minimize(nll, initial,bounds=priors) + vars_ml=soln.x +elif model == 'w-tau-fixed': + if fitnoise: + initial = np.concatenate((np.ones(2*dim),[0.2])) + soln = minimize(nll, initial,bounds=priors) + vars_ml=soln.x + else: + initial = np.ones(2*dim) + soln = minimize(nll, initial,bounds=priors) + vars_ml=soln.x +else: + if fitnoise: + initial = np.concatenate((np.ones(ndim),[1])) + soln = minimize(nll, initial,bounds=priors) + vars_ml=soln.x + else: + initial = np.ones(ndim) + soln = minimize(nll, initial,bounds=priors) + vars_ml=soln.x +print("best fit pars from fit: ",vars_ml) + + +# In[50]: + + +mypool = Pool(nbcores) +mypool.size = nbcores + +start = time.process_time() +f2=dynesty.NestedSampler(rdown_pe.log_likelihood,rdown_pe.prior_transform, len(priors), nlive=npoints,sample=sampler,pool=mypool) +if parser.has_option('setup','dlogz'): + dlogz=np.float(parser.get('setup','dlogz')) + f2.run_nested(dlogz=dlogz,print_progress=False) +else: + f2.run_nested(print_progress=False) + +print(time.process_time() - start) + + +# In[52]: + + +res = f2.results +res.samples_u.shape +res.summary() +samps=f2.results.samples +postsamps = rd_ut.posterior_samples(f2) +samps_tr=np.transpose(samps) +half_points=int(round((len(samps_tr[0])/1.25))) +evidence = res.logz[-1] +evidence_error = res.logzerr[-1] +if export: + rd_ut.save_object(res, results_file) + + +# In[53]: + + +pars = nmax,model,samps_tr, half_points +npamps = rd_ut.get_best_amps(pars,parser=parser,nr_code=nr_code) + + +# In[54]: + + +if export: + pars = simulation_number, nmax, tshift, evidence, evidence_error + rd_ut.export_logz_files(sumary_data,pars) + + +# In[55]: + + +labels = rd_ut.define_labels(dim,model,fitnoise) +if export: + pars = tshift, len(priors), labels + rd_ut.export_bestvals_files(best_data,postsamps,pars) + + +# In[56]: + + +w, tau = rdown.QNM_spectrum() +pars = w, tau, mf, af, npamps +truths = rd_ut.get_truths(model,pars,fitnoise) + + +# In[57]: + + +fg=corner.corner(postsamps,quantiles=[0.05,0.5,0.95],show_titles=True,max_n_ticks = 4,bins=50,truths=truths,labels=labels,truth_color='red') +plt.show() +if export: + fg.savefig(corner_plot, format = 'png', bbox_inches = 'tight') + + +# In[58]: + + +from importlib import reload +reload(rd_ut) +if model == 'w-tau-fixed-m-af' and export == True: + truths=np.concatenate((w,tau)) + labels_mf = np.concatenate((w_lab,tau_lab)) + new_samples = rd_ut.convert_m_af_2_w_tau_post(res,fitnoise=False) + figure = corner.corner(new_samples,truths=truths,quantiles=[0.05,0.95],labels=labels_mf,smooth=True,color='b',truth_color='r',show_titles=True) + figure.savefig(corner_plot_extra, format = 'png', bbox_inches = 'tight') + + +# In[151]: + + +#lnz_truth = ndim * -np.log(2 * 10.) # analytic evidence solution +fig, axes = dyplot.runplot(res) +fig.tight_layout() +if export: + fig.savefig(diagnosis_plot, format = 'png', dpi = 384, bbox_inches = 'tight') + + +# In[166]: + + +if export: + dict = {'w-tau':rdown.rd_model_wtau , 'w-q': rdown.rd_model_wq, 'w-tau-fixed':rdown.rd_model_wtau_fixed,'w-tau-fixed-m-af': rdown.rd_model_wtau_m_af} + figband = plt.figure(figsize = (12, 9)) + plt.plot(datar_al[:,0].real,datar_al[:,1].real, "green", alpha=0.9, lw=3, label=r'$res_{240}$') + onesig_bounds = np.array([np.percentile(postsamps[:, i], [5, 95]) for i in range(len(postsamps[0]))]).T + samples_1sigma = filter(lambda sample: np.all(onesig_bounds[0] <= sample) and np.all(sample <= onesig_bounds[1]), postsamps) + samples_1sigma_down = list(samples_1sigma)[::downfactor] + for sample in samples_1sigma_down: + plt.plot(datar_al[:,0].real, dict[model](sample).real, "r-", alpha=0.1, lw=1) + plt.title(r'Comparison of the MC fit data and the $1-\sigma$ error band') + plt.legend() + plt.xlabel('t') + plt.ylabel('h') + plt.show() + figband.savefig(fit_plot) + + +# In[162]: + + +if export: + with open(samples_file,'w') as file: + writer = csv.writer(file) + writer.writerow(labels) + writer.writerows(samps[::downfactor]) + diff --git a/code_new/RD_Dynesty_Fits/build/lib/RD_Dynesty_Fits/__init__.py b/code_new/RD_Dynesty_Fits/build/lib/RD_Dynesty_Fits/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..8b137891791fe96927ad78e64b0aad7bded08bdc --- /dev/null +++ b/code_new/RD_Dynesty_Fits/build/lib/RD_Dynesty_Fits/__init__.py @@ -0,0 +1 @@ + diff --git a/code_new/RD_Dynesty_Fits/build/lib/RD_Dynesty_Fits/rdown.py b/code_new/RD_Dynesty_Fits/build/lib/RD_Dynesty_Fits/rdown.py new file mode 100644 index 0000000000000000000000000000000000000000..1357ccbf98a454670c79fb49574d7fe1447e243a --- /dev/null +++ b/code_new/RD_Dynesty_Fits/build/lib/RD_Dynesty_Fits/rdown.py @@ -0,0 +1,208 @@ +# Copyright (C) 2021 Xisco Jimenez Forteza +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + +# +# ============================================================================= +# +# Preamble +# +# ============================================================================= +# +# Module to generate RD waveforms. + +import numpy as np +import qnm +import os + +f_fpars= [[2.95845, -2.58697, 0.0533469], [2.12539, -1.78054, 0.0865503], [1.74755, -1.44776, 0.123666], [1.78287, -1.53203, 0.129475], [2.04028, -1.83224, 0.112497]] +q_fpars=[[0.584077, 1.52053, -0.480658], [0.00561441, 0.630715, -0.432664], [-0.197965, 0.515956, -0.369706], [-0.275097, 0.455691, -0.331543], [-0.287596, 0.398514, -0.309799]] + + +c=2.99792458*10**8;G=6.67259*10**(-11);MS=1.9885*10**30; +class Ringdown_Spectrum: + """RDown model generator""" + def __init__(self,mf,af,l,m,n=4,s=-2,time=[],fixed=False,qnm_model='berti'): + self.mf = mf + self.af = af + self.l = l + self.m = m + self.n = n + self.time = time + self.grav_220 = [qnm.modes_cache(s=s,l=self.l,m=self.m,n=i) for i in range (0,self.n+1)] + self.dim = self.n+1 + self.fixed = fixed + self.qnm_model = qnm_model + dict_omega = {'berti': self.QNM_Berti , 'qnm': self.QNM_spectrum} + dic = {'w-tau':self.rd_model_wtau , 'w-q': self.rd_model_wq, 'w-tau-fixed':self.rd_model_wtau_fixed,'w-tau-fixed-m-af': self.rd_model_wtau_m_af} + + if len(self.time)==0: + self.time = np.arange(0,100,0.1) + + if self.fixed: + omegas_new=np.asarray([self.grav_220[i](a=self.af)[0] for i in range (0,self.dim)]) + self.w = (np.real(omegas_new))/self.mf + self.tau=-1/(np.imag(omegas_new))*self.mf + + + def QNM_spectrum(self): + """ It computes the RD frequencies and damping times in NR units. + """ + omegas_new=np.asarray([self.grav_220[i](a=self.af)[0] for i in range (0,self.n+1)]) + w_m_a = (np.real(omegas_new))/self.mf + tau_m_a=-1/(np.imag(omegas_new))*self.mf + + return (w_m_a, tau_m_a) + + def QNM_Berti(self,rdowndata): + """ It computes the RD frequencies and damping times in NR units. + """ + position=np.argmax(rdowndata[0,0] >= (self.af)) + #w_m_a=f1+f2*(1-af)**f3 + w_m_a=[None]*(self.n+1) + tau_ma_a=[None]*(self.n+1) + + for i in range(self.n+1): + qnm=rdowndata[i,1:3,position] + w_m_a[i] = qnm[0]/self.mf + tau_ma_a[i] = -1/(qnm[1])*self.mf + + return w_m_a, tau_ma_a + + + def w_fpars_Berti(self,n): + return f_fpars[n] + + def tau_qpars_Berti(self,n): + return q_fpars[n] + + def mass_from_wtau(self,n,w,tau): + f1,f2,f3 = w_fpars_Berti(n) + q1,q2,q3 = tau_qpars_Berti(n) + res=(f1 + f2*(2**(-1/q3)*((-2*q1 + w*tau)/q2)**(1/q3))**f3)/w + return res + + def spin_from_wtau(self,n,w,tau): + f1,f2,f3 = w_fpars_Berti(n) + q1,q2,q3 = tau_qpars_Berti(n) + res=1 - 2**(-1/q3)*((-2*q1 + w*tau)/q2)**(1/q3) + return res + + def mass_from_wtau_loop(self,w,tau,l,m): + res=[None]*dim + for n in range (0,dim): + f1,f2,f3 = w_fpars_Berti(n) + q1,q2,q3 = tau_qpars_Berti(n) + res[n]=(f1 + f2*(2**(-1/q3)*((-2*q1 + w[n]*tau[n])/q2)**(1/q3))**f3)/w[n] + return res + + def spin_from_wtau_loop(self,w,tau,l,m): + res=[None]*dim + for n in range (0,dim): + f1,f2,f3 = w_fpars_Berti(n) + q1,q2,q3 = tau_qpars_Berti(n) + res[n]= 1 - 2**(-1/q3)*((-2*q1 + w[n]*tau[n])/q2)**(1/q3) + return res + + + def rd_model_wtau(self,theta): + """RD model parametrized with the damping time tau. + """ + assert int(len(theta)/4) == self.dim, 'Please recheck your n and parameters' + + wvars = theta[ : (self.dim)] + tvars = theta[(self.dim) : 2*(self.dim)] + xvars = theta[2*(self.dim) : 3*(self.dim)] + yvars = theta[3*(self.dim) : ] + + ansatz = 0 + for i in range (0,self.dim): + ansatz += (xvars[i]*np.exp(1j*yvars[i]))*np.exp(-self.time/tvars[i]) * (np.cos(wvars[i]*self.time)-1j*np.sin(wvars[i]*self.time)) + # -1j to agree with SXS convention + return ansatz + + def rd_model_wtau_m_af(theta): + """RD model parametrized with the damping time tau and with the QNM spectrum fixd to GR. The QNM spectrum is given from the mass and spin. + """ + xvars = theta[ : (dim)] + yvars = theta[(dim) : 2*(dim)] + mass_vars = theta[index_mass] + spin_vars = theta[index_spin] + + w_m_a , tau_m_a = dict_omega[self.qnm_model](mass_vars,spin_vars,2,2) + + ansatz = 0 + for i in range (0,dim): + ansatz += (xvars[i]*np.exp(1j*yvars[i]))*np.exp(-timesrd_final_tsh/tau_m_a[i]) * (np.cos(w_m_a[i]*timesrd_final_tsh)-1j*np.sin(w_m_a[i]*timesrd_final_tsh)) + # -1j to agree with SXS convention + return ansatz + + def rd_model_wtau_fixed(theta): + """RD model parametrized with the damping time tau and with the QNM spectrum fixd to GR. + """ + xvars = theta[ : (dim)] + yvars = theta[(dim) : 2*(dim)] + + ansatz = 0 + for i in range (0,dim): + ansatz += (xvars[i]*np.exp(1j*yvars[i]))*np.exp(-timesrd_final_tsh/tau[i]) * (np.cos(w[i]*timesrd_final_tsh)-1j*np.sin(w[i]*timesrd_final_tsh)) + # -1j to agree with SXS convention + return ansatz + + def rd_model_wq(self,theta): + """RD model parametrized with the quality factor q. + """ + assert int(len(theta)/4) == self.dim, 'Please recheck your n and parameters' + + wvars = theta[ : (self.dim)] + qvars = theta[(self.dim) : 2*(self.dim)] + xvars = theta[2*(self.dim) : 3*(self.dim)] + yvars = theta[3*(self.dim) : ] + + ansatz = 0 + for i in range (0,self.dim): + ansatz += (xvars[i]*np.exp(1j*yvars[i]))*np.exp(-self.time*np.pi*wvars[i]/qvars[i])*(np.cos(wvars[i]*self.time)-1j*np.sin(wvars[i]*self.time)) + # -1j to agree with SXS convention + return ansatz + + def rd_model_wq_fixed(self,theta): + """RD model parametrized with the damping time tau and with the QNM spectrum fixd to GR. + """ + xvars = theta[ : (self.dim)] + yvars = theta[(self.dim) : 2*(self.dim)] + + ansatz = 0 + for i in range (0,self.dim): + ansatz += (xvars[i]*np.exp(1j*yvars[i]))*np.exp(-self.time/self.tau[i]) * (np.cos(self.w[i]*self.time)-1j*np.sin(self.w[i]*self.time)) + # -1j to agree with SXS convention + return ansatz + + + def rd_model_wq_m_a(self,theta): + """RD model parametrized with the damping time tau and with the QNM spectrum fixd to GR. The QNM spectrum is given from the mass and spin. + """ + xvars = theta[ : (self.dim)] + yvars = theta[(self.dim) : 2*(self.dim)] + mass_vars = theta[-2] + spin_vars = theta[-1] + + w_m_a , tau_m_a = QNM_spectrum() + + ansatz = 0 + for i in range (0,dim): + ansatz += (xvars[i]*np.exp(1j*yvars[i]))*np.exp(-timesrd_final_tsh/tau_m_a[i]) * (np.cos(w_m_a[i]*timesrd_final_tsh)-1j*np.sin(w_m_a[i]*timesrd_final_tsh)) + # -1j to agree with SXS convention + return ansatz \ No newline at end of file diff --git a/code_new/RD_Dynesty_Fits/build/lib/RD_Dynesty_Fits/rdown_pe.py b/code_new/RD_Dynesty_Fits/build/lib/RD_Dynesty_Fits/rdown_pe.py new file mode 100644 index 0000000000000000000000000000000000000000..c92e073cac48d68b9fb46fc44a03b6e1c2c8af65 --- /dev/null +++ b/code_new/RD_Dynesty_Fits/build/lib/RD_Dynesty_Fits/rdown_pe.py @@ -0,0 +1,191 @@ +# Copyright (C) 2021 Xisco Jimenez Forteza +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + +# +# ============================================================================= +# +# Preamble +# +# ============================================================================= +# +# Module to run PE on RD data +import random +from multiprocessing import Pool +import dynesty +import numpy as np +import rdown + +class Ringdown_PE: + def __init__(self,rdown_fun,data,dim,priors,errors2=1,theta=[],model='w-tau',norm_factor=0,l_int=0): + self.dim = dim + self.rdown_fun = rdown_fun + self.times = data[:,0] + self.datare = data[:,1].real + self.dataim = data[:,1].imag + self.priors = priors + self.priors_min = priors[:,0] + self.priors_max = priors[:,1] + self.prior_dim = len(priors) + self.errors2 = errors2 + self.norm_factor = norm_factor + self.model = model + self.l_int = l_int + self.theta = theta + self.dict = {'w-tau':rdown_fun.rd_model_wtau , 'w-q': rdown_fun.rd_model_wq, 'w-tau-fixed':rdown_fun.rd_model_wtau_fixed,'w-tau-fixed-m-af': rdown_fun.rd_model_wtau_m_af} + + #def log_likelihood(self,theta,sigma=1): + # """chi2 likelihood. + # """ + # modelev = dict[model](theta) + # result = -np.sum(((gwdatanew_re_tsh - modelev.real)**2+(gwdatanew_im_tsh - modelev.imag)**2)/(2*theta[-1]*error_final)) + # if np.isnan(result): + # return -np.inf + # return result + + def log_likelihood(self,theta,sigma=1): + """chi2 likelihood. + """ + modelev = self.dict[self.model](theta) + modelevre= modelev.real + modelevim= modelev.imag + + sigma2 = self.errors2 + self.l_int*(self.datare** 2+self.dataim**2) * np.exp(2 * theta[-1]) + + result = -0.5*np.sum(((self.datare - modelevre)**2+(self.dataim - modelevim)**2)/sigma2+self.l_int*(np.log(2*np.pi*sigma2)))-self.l_int*self.norm_factor + + if np.isnan(result): + return -np.inf + return result + + + def prior_transform(self,cube): + """RD uniform priors. The values for priors_min and priors_max must be given out of this function. + """ + for i in range(self.prior_dim): + cube[i] = self.priors_min[i]+ cube[i]*(self.priors_max[i]-self.priors_min[i]) + return cube + +def load_priors(model,config_parser,nmax,fitnoise=True): + # loading priors + if model == 'w-q': + tau_var_str='q' + else: + tau_var_str='tau' + + if model == 'w-tau': + w_mins=np.empty(nmax+1) + w_maxs=np.empty(nmax+1) + tau_mins=np.empty(nmax+1) + tau_maxs=np.empty(nmax+1) + a_mins=np.empty(nmax+1) + a_maxs=np.empty(nmax+1) + ph_mins=np.empty(nmax+1) + ph_maxs=np.empty(nmax+1) + + for i in range(nmax+1): + wp_min=config_parser.get('prior-w'+str(i),'w'+str(i)+'_min') + w_mins[i] = np.float(wp_min) + + wp_max=config_parser.get('prior-w'+str(i),'w'+str(i)+'_max') + w_maxs[i] = np.float(wp_max) + + taup_min=config_parser.get('prior-'+tau_var_str+str(i),tau_var_str+str(i)+'_min') + tau_mins[i] = np.float(taup_min) + + taup_max=config_parser.get('prior-'+tau_var_str+str(i),tau_var_str+str(i)+'_max') + tau_maxs[i] = np.float(taup_max) + + amp0_min=config_parser.get('prior-amp'+str(i),'amp'+str(i)+'_min') + a_mins[i] = np.float(amp0_min) + + amp1_max=config_parser.get('prior-amp'+str(i),'amp'+str(i)+'_max') + a_maxs[i] = np.float(amp1_max) + + phase_min=config_parser.get('prior-phase'+str(i),'phase'+str(i)+'_min') + ph_mins[i] = np.float(phase_min)*2*np.pi + + phase_max=config_parser.get('prior-phase'+str(i),'phase'+str(i)+'_max') + ph_maxs[i] = np.float(phase_max)*2*np.pi + + priors_min = np.concatenate((w_mins,tau_mins,a_mins,ph_mins)) + priors_max = np.concatenate((w_maxs,tau_maxs,a_maxs,ph_maxs)) + prior_dim = len(priors_min) + priors=np.column_stack((priors_min,priors_max)) + + if model == 'w-tau-fixed': + a_mins=np.empty(nmax+1) + a_maxs=np.empty(nmax+1) + ph_mins=np.empty(nmax+1) + ph_maxs=np.empty(nmax+1) + + for i in range(nmax+1): + amp0_min=config_parser.get('prior-amp'+str(i),'amp'+str(i)+'_min') + a_mins[i] = np.float(amp0_min) + + amp1_max=config_parser.get('prior-amp'+str(i),'amp'+str(i)+'_max') + a_maxs[i] = np.float(amp1_max) + + phase_min=config_parser.get('prior-phase'+str(i),'phase'+str(i)+'_min') + ph_mins[i] = np.float(phase_min)*2*np.pi + + phase_max=config_parser.get('prior-phase'+str(i),'phase'+str(i)+'_max') + ph_maxs[i] = np.float(phase_max)*2*np.pi + + + priors_min = np.concatenate((a_mins,ph_mins)) + priors_max = np.concatenate((a_maxs,ph_maxs)) + prior_dim = len(priors_min) + priors=np.column_stack((priors_min,priors_max)) + + elif model == 'w-tau-fixed-m-af': + a_mins=np.empty(nmax+1) + a_maxs=np.empty(nmax+1) + ph_mins=np.empty(nmax+1) + ph_maxs=np.empty(nmax+1) + + for i in range(nmax+1): + amp0_min=config_parser.get('prior-amp'+str(i),'amp'+str(i)+'_min') + a_mins[i] = np.float(amp0_min) + + amp1_max=config_parser.get('prior-amp'+str(i),'amp'+str(i)+'_max') + a_maxs[i] = np.float(amp1_max) + + phase_min=config_parser.get('prior-phase'+str(i),'phase'+str(i)+'_min') + ph_mins[i] = np.float(phase_min)*2*np.pi + + phase_max=config_parser.get('prior-phase'+str(i),'phase'+str(i)+'_max') + ph_maxs[i] = np.float(phase_max)*2*np.pi + + mass_min=[np.float(config_parser.get('prior-mass','mass_min'))] + mass_max=[np.float(config_parser.get('prior-mass','mass_max'))] + spin_min=[np.float(config_parser.get('prior-spin','spin_min'))] + spin_max=[np.float(config_parser.get('prior-spin','spin_max'))] + priors_min = np.concatenate((a_mins,ph_mins,mass_min,spin_min)) + priors_max = np.concatenate((a_maxs,ph_maxs,mass_max,spin_max)) + prior_dim = len(priors_min) + priors=np.column_stack((priors_min,priors_max)) + + + if fitnoise: + priors_fit_min=[np.float(config_parser.get('prior-noise','noise_min'))] + priors_fit_max=[np.float(config_parser.get('prior-noise','noise_max'))] + priors_min = np.concatenate((priors_min,priors_fit_min)) + priors_max = np.concatenate((priors_max,priors_fit_max)) + priors=np.column_stack((priors_min,priors_max)) + prior_dim = len(priors_min) + + return priors \ No newline at end of file diff --git a/code_new/RD_Dynesty_Fits/build/lib/RD_Dynesty_Fits/rdown_utilities.py b/code_new/RD_Dynesty_Fits/build/lib/RD_Dynesty_Fits/rdown_utilities.py new file mode 100644 index 0000000000000000000000000000000000000000..c4a5b95c1c26beb418d2457fbd2a2b09212778c3 --- /dev/null +++ b/code_new/RD_Dynesty_Fits/build/lib/RD_Dynesty_Fits/rdown_utilities.py @@ -0,0 +1,318 @@ +# Copyright (C) 2021 Xisco Jimenez Forteza +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + +# +# ============================================================================= +# +# Preamble +# +# ============================================================================= +# +# Module to run PE on RD data +import numpy as np +from dynesty.utils import resample_equal +from dynesty import utils as dyfunc +import os +import csv +import pandas as pd +import pickle + +def posterior_samples(sampler): + """ + Returns posterior samples from nested samples and weights + given by dynsety sampler + """ + + dynesty_samples = sampler.results['samples'] + wt = np.exp(sampler.results['logwt'] - + sampler.results['logz'][-1]) + # Make sure that sum of weights equal to 1 + weights = wt/np.sum(wt) + posterior_dynesty = dyfunc.resample_equal(dynesty_samples, weights) + return posterior_dynesty + +def FFT_FreqBins(times): + Len = len(times) + DeltaT = times[-1]- times[0] + dt = DeltaT/(Len-1) + dnu = 1/(Len*dt) + maxfreq = 1/(2*dt) + add = dnu/4 + + p = np.arange(0.0,maxfreq+add,dnu) + m = np.arange(p[-1]-(2*maxfreq)+dnu,-dnu/2+add,dnu) + res=np.concatenate((p,m)) + + return res + +def hFromPsi4FFI(tpsi4,f0): + + timecheck1=tpsi4[-2,0]-tpsi4[-1,0] + timecheck2=tpsi4[1,0]-tpsi4[0,0] + + if np.abs(timecheck1-timecheck2)>=0.0001: + print("The data might not be equally sampled!!") + + times,data= tpsi4[:,0],tpsi4[:,1] + + freqs = FT_FreqBins(xaxis.real).real + position = np.argmax(freqs >= f0) + freqs[:position]=f0*np.ones(len(freqs[:position])) + freqs=2*np.pi*freqs + + fdata=fft(data) + len(myTable)*ifft(- fdata/floor**2); + np.stack((times,data)).T + + +def twopoint_autocovariance(t,n): + """ It computes the two-point autocovariance function. + """ + dt=t[1]-t[0] + res = np.zeros(len(n)) + taus = np.zeros(len(n)) + for tau in range(0,int(len(n)/2)): + ntau=np.roll(n, tau) + taus[tau] = t[tau] + res[tau]=np.sum(n*ntau).real + return (taus[:int(len(n)/2)],res[:int(len(n)/2)]) + +def save_object(obj, filename): + with open(filename, 'wb') as output: # Overwrites any existing file. + pickle.dump(obj, output, pickle.HIGHEST_PROTOCOL) + + +def EasyMatchT(t,h1,h2,tmin,tmax): + """ It computes the time-domain match for (h1|h2) complex waveforms. + """ + pos = np.argmax(t >= (tmin)); + + h1red=h1[pos:]; + h2red=h2[pos:]; + + norm1=np.sum(np.abs(h1red)**2) + norm2=np.sum(np.abs(h2red)**2) + + myTable=h1red*np.conjugate(h2red) + res=((np.sum(myTable)/np.sqrt(norm1*norm2))).real + + return res + +def EasySNRT(t,h1,h2,tmin,tmax): + """ It computes the time-domain snr for (h1|h2) complex waveforms. + """ + pos = np.argmax(t >= (tmin)); + + h1red=h1[pos:]; + h2red=h2[pos:]; + + myTable=h1red*np.conjugate(h2red) + res=2*np.sqrt((np.sum(myTable)).real) + + return res + +def FindTmaximum(y): + """ It determines the maximum absolute value of the complex waveform. + """ + absval = np.sqrt(y[:,1]*y[:,1]+y[:,2]*y[:,2]) + vmax=np.max(absval) + index = np.argmax(absval == vmax) + timemax=y[index,0] + + return timemax + +def export_logz_files(output_file,pars): + sim_num, nmax, tshift, evidence, evidence_error = pars + + """ + Generate the logz.csv files you want to export the data to. + file_type must be one of this options: [corner_plot,corner_plot_extra,diagnosis,fit,post_samples,sampler_results,log_z] + """ + + summary_titles=['n','id','t_shift','dlogz','dlogz_err'] + if os.path.exists(output_file): + outvalues = np.array([[nmax, sim_num, tshift, evidence,evidence_error]]) + else: + outvalues = np.array([summary_titles,[nmax, sim_num, tshift, evidence,evidence_error]]) + + with open(output_file, 'a') as file: + writer = csv.writer(file) + if (outvalues.shape)[0]>1 : + writer.writerows(outvalues) + else: + writer.writerow(outvalues[0]) + + return + +def export_bestvals_files(best_data_file,postsamps,pars): + + tshift, lenpriors, labels = pars + + sigma_vars_m = np.empty(lenpriors) + sigma_vars_p = np.empty(lenpriors) + sigma_vars = np.empty(lenpriors) + sigma_vars_ml = np.empty(lenpriors) + for i in range(lenpriors): + amps_aux = postsamps[:,i] + sigma_vars_m[i] = np.quantile(amps_aux, 0.05) + sigma_vars[i] = np.quantile(amps_aux, 0.5) + sigma_vars_ml[i] = postsamps[-1,i] + sigma_vars_p[i] = np.quantile(amps_aux, 0.95) + + sigma_vars_all = [sigma_vars,sigma_vars_ml,sigma_vars_m,sigma_vars_p] + sigma_vars_all=np.stack([sigma_vars,sigma_vars_ml,sigma_vars_m,sigma_vars_p], axis=0) + + key =['max val','max val ml','lower bound','higher bound'] + dfslist = [pd.DataFrame(np.concatenate(([tshift],sigma_vars_all[i])).reshape((-1,lenpriors+1)), columns=np.concatenate((['tshift'],labels)), index = [key[i]]) for i in range(4)] + df2 = pd.concat(dfslist) + if os.path.exists(best_data_file): + df2.to_csv(best_data_file, mode='a', header=False,index = True) + else: + df2.to_csv(best_data_file, index = True) + + + +def define_labels(dim,model,fitnoise): + wstr = r'$\omega_' + + if model == 'w-tau': + taustr = r'$\tau_' + elif model == 'w-q': + taustr = r'$q_' + elif model == 'w-tau-fixed': + taustr = r'$dumb_var}' + elif model == 'w-tau-fixed-m-af': + taustr = r'$\tau_' + + ampstr = r'$A_' + phasestr = r'$\phi_' + + w_lab = [None] * dim + tau_lab = [None] * dim + amp_lab = [None] * dim + pha_lab = [None] * dim + mass_lab = ['mass'] + spin_lab = ['spin'] + + for i in range(dim): + w_lab[i] = wstr+str(i)+'$' + tau_lab[i] = taustr+str(i)+'$' + amp_lab[i] = ampstr+str(i)+'$' + pha_lab[i] = phasestr+str(i)+'$' + + + labels = np.concatenate((w_lab,tau_lab,amp_lab,pha_lab)) + + if model=='w-tau-fixed': + labels = np.concatenate((amp_lab,pha_lab)) + + if model=='w-tau-fixed-m-af': + pha_lab[i] = phasestr+str(i)+'$' + + labels = np.concatenate((amp_lab,pha_lab,mass_lab,spin_lab)) + + if fitnoise: + noise_lab = ['noise'] + labels = np.concatenate((labels,noise_lab)) + + return labels + +def get_truths(model,pars,fitnoise): + w, tau, mf, af , npamps = pars + if model == 'w-q': + tau_val = np.pi*w*tau + truths = np.concatenate((w,tau_val,npamps)) + elif model == 'w-tau': + tau_val = tau + truths = np.concatenate((w,tau_val,npamps)) + elif model == 'w-tau-fixed': + truths = npamps + elif model == 'w-tau-fixed-m-af': + truths = np.concatenate((npamps,[mf],[af])) + + if fitnoise: + truths = np.concatenate((truths,[1])) + + return truths + +def get_best_amps(pars,parser=None,nr_code=None): + nmax,model,samps_tr,half_points = pars + + + if model=='w-tau-fixed': + rg = (nmax+1) + elif model=='w-tau-fixed': + rg = (nmax+1)+2 + else: + rg = (nmax+1)*2 + + + if model=='w-tau-fixed-a-mf': + npamps = np.empty((nmax+1)) + for i in range(0,(nmax+1)): + amps_aux = samps_tr[i+rg][half_points:-1] + npamps[i] = np.quantile(amps_aux, 0.5) + else : + npamps = np.empty((nmax+1)*2) + for i in range(0,(nmax+1)*2): + amps_aux = samps_tr[i][half_points:-1] + npamps[i] = np.quantile(amps_aux, 0.5) + + if nr_code == 'Mock-data': + nm_mock = parser.get('rd-mock-parameters','nm_mock') + nm_mock = np.int(nm_mock) + amp_mock=np.empty(nm_mock+1) + ph_mock=np.empty(nm_mock+1) + for i in range(nm_mock+1): + amp_mockp = parser.get('rd-mock-parameters','amp'+str(i)) + amp_mock[i] = np.float(amp_mockp) + ph_mockp=parser.get('rd-mock-parameters','phase'+str(i)) + ph_mock[i] = np.float(ph_mockp) + + npamps = np.concatenate((amp_mock,ph_mock)) + return npamps + +def convert_m_af_2_w_tau_post(res,fitnoise=False): + + samples_2=res.samples + samps=f2.results.samples + + if fitnoise: + fmass_spin=(samps.T)[-3:-1].T + else: + fmass_spin=(samps.T)[-2:].T + #fmass_spin=new_samples[-2:] + fmass_spin_dist=[None]*len(fmass_spin) + weight=np.exp(res.logwt - res.logz[-1]) + for i in range(len(fmass_spin)): + fmass_spin_dist[i]=np.concatenate(dict_omega[qnm_model](fmass_spin[i,0],fmass_spin[i,1],2,2)) + + fmass_spin_dist_v2=np.asarray(fmass_spin_dist) + new_samples = dyfunc.resample_equal(fmass_spin_dist_v2, weight) + + return new_samples + +def save_object(obj, filename): + with open(filename, 'wb') as output: # Overwrites any existing file. + pickle.dump(obj, output, pickle.HIGHEST_PROTOCOL) + +def rm_files(files): + """ rm all old files """ + for i in files: + if os.path.exists(i): + os.remove(i) + \ No newline at end of file diff --git a/code_new/RD_Dynesty_Fits/build/lib/RD_Dynesty_Fits/read_data.py b/code_new/RD_Dynesty_Fits/build/lib/RD_Dynesty_Fits/read_data.py new file mode 100644 index 0000000000000000000000000000000000000000..87185de6364a1b89cb9223329e31dc5bb3e58391 --- /dev/null +++ b/code_new/RD_Dynesty_Fits/build/lib/RD_Dynesty_Fits/read_data.py @@ -0,0 +1,344 @@ +# Copyright (C) 2021 Xisco Jimenez Forteza +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + +# +# ============================================================================= +# +# Preamble +# +# ============================================================================= +# +# Module to run PE on RD data +import numpy as np +import rdown_utilities as rd_ut +import romspline +import rdown as rd +import h5py +import json +from scipy import interpolate +from scipy.interpolate import interp1d + + +def read_data(nr_code,sim_path,mf=1,af=0,parser=None,RD=True,tshift=0,tend = 100,metadata_file=None): + if nr_code=='SXS': + gw = {} + gw = h5py.File(sim_path, 'r') + gw_data = gw["Extrapolated_N3.dir"]["Y_l2_m2.dat"] + times = gw_data[:,0] + + metadata = {} + with open(metadata_file) as file: + metadata = json.load(file) + + af = metadata['remnant_dimensionless_spin'][-1] + mf = metadata['remnant_mass'] + + tmax=rd_ut.FindTmaximum(gw_data[round(len(gw_data)/2):]) + times = times - tmax + + if RD: + position = np.argmax(times >= 0) + gw_data = gw_data[:,1][position:]+1j*gw_data[:,2][position:] + times = times[times >= 0] + + elif nr_code=='Maya': + dt=0.1 + gw = {} + gw = h5py.File(sim_path, 'r') + gw_sxs_bbh_0305_amp = np.asarray(gw['amp_l2_m2/Y'])[6:] + times_1 = np.asarray(gw['amp_l2_m2/X'])[6:] + gw_sxs_bbh_0305_amp_int = romspline.ReducedOrderSpline(times_1, gw_sxs_bbh_0305_amp) + gw_sxs_bbh_0305_pha = np.asarray(gw['phase_l2_m2/Y'])[6:] + times = np.asarray(gw['phase_l2_m2/X'])[6:] + gw_sxs_bbh_0305_pha_int = romspline.ReducedOrderSpline(times, gw_sxs_bbh_0305_pha) + + tmin=max(times_1[0],times[0]) + tmax=min(times_1[-1],times[-1]) + times=np.arange(tmin,tmax,dt) + amps=gw_sxs_bbh_0305_amp_int(times) + phs=gw_sxs_bbh_0305_pha_int(times) + gw_sxs_bbh_0305 = np.asarray([times,amps*np.cos(phs),amps*np.sin(phs)]).T + gw5_sxs_bbh_0305 = gw_sxs_bbh_0305 + + times = gw_sxs_bbh_0305[:,0] + tmax=rd_ut.FindTmaximum(gw_sxs_bbh_0305[round(len(gw_sxs_bbh_0305)/2):]) + times = times - tmax + + #times 6--> x axis of your data + times5 = gw5_sxs_bbh_0305[:,0] + tmax5=rd_ut.FindTmaximum(gw5_sxs_bbh_0305[round(len(gw_sxs_bbh_0305)/2):]) + times5 = times5 - tmax5 + #Select the data from 0 onwards + position = np.argmax( times >= (t_align)) + position5 = np.argmax(times5 >= (t_align)) + gw_sxs_bbh_0305rd=gw_sxs_bbh_0305[position+1:] + gw_sxs_bbh_0305rd5=gw5_sxs_bbh_0305[position5+1:] + timesrd=gw_sxs_bbh_0305[position:-1][:,0][:] + timesrd5=gw5_sxs_bbh_0305[position5:-1][:,0][:] + + elif nr_code=='LaZeV': + dt=0.1 + gw = {} + gw = h5py.File(simulation_path_1, 'r') + gw_sxs_bbh_0305_amp = np.asarray(gw['amp_l2_m2/Y'])[6:] + times_1 = np.asarray(gw['amp_l2_m2/X'])[6:] + gw_sxs_bbh_0305_amp_int = romspline.ReducedOrderSpline(times_1, gw_sxs_bbh_0305_amp) + gw_sxs_bbh_0305_pha = np.asarray(gw['phase_l2_m2/Y'])[6:] + times = np.asarray(gw['phase_l2_m2/X'])[6:] + gw_sxs_bbh_0305_pha_int = romspline.ReducedOrderSpline(times, gw_sxs_bbh_0305_pha) + + tmin=max(times_1[0],times[0]) + tmax=min(times_1[-1],times[-1]) + times=np.arange(tmin,tmax,dt) + amps=gw_sxs_bbh_0305_amp_int(times) + phs=gw_sxs_bbh_0305_pha_int(times) + gw_sxs_bbh_0305 = np.asarray([times,amps*np.cos(phs),amps*np.sin(phs)]).T + gw5_sxs_bbh_0305 = gw_sxs_bbh_0305 + + times = gw_sxs_bbh_0305[:,0] + tmax=rd_ut.FindTmaximum(gw_sxs_bbh_0305[round(len(gw_sxs_bbh_0305)/2):]) + times = times - tmax + + #times 6--> x axis of your data + times5 = gw5_sxs_bbh_0305[:,0] + tmax5=rd_ut.FindTmaximum(gw5_sxs_bbh_0305[round(len(gw_sxs_bbh_0305)/2):]) + times5 = times5 - tmax5 + + #Select the data from 0 onwards + position = np.argmax( times >= (t_align)) + position5 = np.argmax(times5 >= (t_align)) + gw_sxs_bbh_0305rd=gw_sxs_bbh_0305[position+1:] + gw_sxs_bbh_0305rd5=gw5_sxs_bbh_0305[position5+1:] + timesrd=gw_sxs_bbh_0305[position:-1][:,0][:] + timesrd5=gw5_sxs_bbh_0305[position5:-1][:,0][:] + + elif nr_code=='Mock-data': + times = np.arange(tshift,tend+10,0.1) + + nm_mock = parser.get('rd-mock-parameters','nm_mock') + nm_mock = np.int(nm_mock) + mf = parser.get('rd-mock-parameters','mf') + mf = np.float(mf) + af = np.float(parser.get('rd-mock-parameters','af')) + af = np.float(af) + + rdown=rd.Ringdown_Spectrum(mf,af,2,2,n=nm_mock,s=-2,time=times) + + w_mock=np.empty(nm_mock+1) + tau_mock=np.empty(nm_mock+1) + amp_mock=np.empty(nm_mock+1) + ph_mock=np.empty(nm_mock+1) + + for i in range(nm_mock+1): + wp_mock = parser.get('rd-mock-parameters','w'+str(i)) + w_mock[i] = np.float(wp_mock) + tp_mock=parser.get('rd-mock-parameters','tau'+str(i)) + tau_mock[i] = np.float(tp_mock) + amp_mockp = parser.get('rd-mock-parameters','amp'+str(i)) + amp_mock[i] = np.float(amp_mockp) + ph_mockp=parser.get('rd-mock-parameters','phase'+str(i)) + ph_mock[i] = np.float(ph_mockp) + + + pars = np.concatenate((w_mock,tau_mock,amp_mock,ph_mock)) + gw_data=rdown.rd_model_wtau(pars) + + return np.stack((times,gw_data)).T + +def nr_resize(data_1,data_2,tshift=0,tend=100): + times_1 = data_1[:,0].real + times_2 = data_2[:,0].real + data_1_re = data_1[:,1].real + data_1_im = data_1[:,1].imag + data_2_re = data_2[:,1].real + data_2_im = data_2[:,1].imag + + gwnew_re = interpolate.interp1d(times_1, data_1_re, kind = 'cubic') + gwnew_im = interpolate.interp1d(times_1, data_1_im, kind = 'cubic') + gwnew_re5 = interpolate.interp1d(times_2, data_2_re, kind = 'cubic') + gwnew_im5 = interpolate.interp1d(times_2, data_2_im, kind = 'cubic') + + if times_2[-1]>= times_1[-1]: + times_rd = times_1 + else: + times_rd = times_2 + + gwdatanew_re = gwnew_re(times_rd) + gwdatanew_im = gwnew_im(times_rd) + gwdatanew_re5 = gwnew_re5(times_rd) + gwdatanew_im5 = gwnew_im5(times_rd) + gwdatanew = gwdatanew_re + 1j*gwdatanew_im + gwdatanew5 = gwdatanew_re5 + 1j*gwdatanew_im5 + + position_in = np.argmax(times_rd >= tshift) + position_end = np.argmax(times_rd >= tend) + times_rd = times_rd[position_in:position_end] + gwdatanew = gwdatanew[position_in:position_end] + gwdatanew5 = gwdatanew5[position_in:position_end] + + return(np.stack((times_rd,gwdatanew)).T,np.stack((times_rd,gwdatanew5)).T) + + +def phase_align(data_1,data_2,t_align=0): + + #timesrd_final = data_1[:,0] + #phas = np.angle(data_1[:,1]) + #phas = np.unwrap(phas) + #phas5 = np.angle(data_2[:,1]) + #phas5 = np.unwrap(phas5) + #position = np.argmax(timesrd_final >= (t_align)) + #dphase = phas5[position]-phas[position] + + #gwdatanew = data_1[:,1]*np.exp(1j*dphase) + + + phas = np.angle(data_1[:,1]) + phas = np.unwrap(phas) + phas5 = np.angle(data_2[:,1]) + phas5 = np.unwrap(phas5) + position = np.argmax(data_1[:,0] >= (0)) + dphase = phas5[position]-phas[position] + gwdatanew = data_1[:,1]*np.exp(1j*dphase) + timesrd_final = data_1[:,0] + + return np.stack((timesrd_final,gwdatanew)).T + +def create_output_files(output_folder,pars,file_type): + sim_num, model, nmax, tshift, npoints = pars + + """ + Generate the output files you want to export the data to. + file_type must be one of this options: [corner_plot,corner_plot_extra,diagnosis,fit,post_samples,sampler_results,log_z] + """ + + if file_type=='corner_plot': + outfile = output_folder+'/Dynesty_'+str(sim_num)+'_'+model+'_nmax_'+str(nmax)+'_tshift_'+str(tshift)+'_'+str(npoints)+'corner_plot.png' + elif file_type=='corner_plot_extra': + outfile = output_folder+'/Dynesty_'+str(sim_num)+'_'+model+'_nmax_'+str(nmax)+'_tshift_'+str(tshift)+'_'+str(npoints)+'corner_plot_extra.png' + elif file_type=='diagnosis': + outfile = output_folder+'/Dynesty_diagnosis'+str(sim_num)+'_'+model+'_nmax_'+str(nmax)+'_tshift_'+str(tshift)+'_'+str(npoints)+'.png' + elif file_type=='fit': + outfile = output_folder+'/Fit_results_'+str(sim_num)+'tshift_'+str(tshift)+'_'+model+'_nmax_'+str(nmax)+'.png' + elif file_type=='post_samples': + outfile = output_folder+'/posterior_samples-'+str(sim_num)+'tshift_'+str(tshift)+'_'+model+'_nmax_'+str(nmax)+'.csv' + elif file_type=='sampler_results': + outfile = output_folder+'/results_'+str(sim_num)+'tshift_'+str(tshift)+'_'+model+'_nmax_'+str(nmax)+'.pkl' + elif file_type=='log_z': + outfile = output_folder+'/summary'+str(sim_num)+'_'+model+'_nmax_'+str(nmax)+'.csv' + elif file_type=='best_vals': + outfile = output_folder+'/best_values_'+str(sim_num)+'_'+model+'_nmax_'+str(nmax)+'.csv' + else: + print ('Something went wrong') + return + + return outfile + +def read_config_file(parser): + # Setup path and output folders + rootpath=parser.get('nr-paths','rootpath') + simulation_path_1 = parser.get('nr-paths','simulation_path_1') + + if parser.get('nr-paths','simulation_path_2'): + simulation_path_2 = parser.get('nr-paths','simulation_path_2') + else: + simulation_path_2 = simulation_path_1 + + metadata_file = parser.get('nr-paths','metadata_json') + simulation_number = parser.get('nr-paths','simulation_number') + simulation_number = np.int(simulation_number) + + output_folder = parser.get('output-folder','output-folder') + if parser.has_option('setup','export'): + export=eval(parser.get('setup','export')) + else: + export=True + + # Setup sampler and output options + overwrite = eval(parser.get('setup','overwrite')) + downfactor = np.int(parser.get('setup','plot_down_factor')) + sampler = parser.get('setup','sampler') + nr_code = parser.get('setup','nr_code') + if parser.has_option('setup','nb_cores'): + nbcores = np.int(parser.get('setup','nb_cores')) + else: + nbcores = 1 + + # time shift , end and align options + tshift=parser.get('time-setup','tshift') + tshift = np.float(tshift) + + tend=parser.get('time-setup','tend') + tend = np.float(tend) + + t_align=parser.get('time-setup','t_align') + t_align = np.float(t_align) + + # n-tones & nlive points + nmax=parser.get('n-tones','nmax') + nmax = np.int(nmax) + + npoints=parser.get('n-live-points','npoints') + npoints = np.int(npoints) + + # setup the RD model + model=parser.get('rd-model','model') + error_str = eval(parser.get('rd-model','error_str')) + fitnoise=eval(parser.get('rd-model','fit_noise')) + if fitnoise: + l_int=1 + index_mass=-3 + index_spin=-2 + # prior_dim = len(priors_min) + else: + index_mass=-2 + index_spin=-1 + l_int=0 + + if error_str: + error_val=np.float(parser.get('rd-model','error_val')) + if error_val==0: + error_type='' + else: + error_type=error_val + else: + error_type='False' + error_val =0 + + if nr_code == 'SXS': + metadata = {} + with open(metadata_file) as file: + metadata = json.load(file) + af = metadata['remnant_dimensionless_spin'][-1] + mf = metadata['remnant_mass'] + else: + mf = parser.get('rd-mock-parameters','mf') + mf = np.float(mf) + af = np.float(parser.get('rd-mock-parameters','af')) + af = np.float(af) + + if model == 'w-q': + tau_var_str='q' + else: + tau_var_str='tau' + + if nr_code == 'Mock-data': + nm_mock = int(parser.get('rd-mock-parameters','nm_mock')) + else: + nm_mock = None + + res = simulation_path_1,simulation_path_2, metadata_file , simulation_number, output_folder, export, overwrite, sampler,nr_code, nbcores,tshift,tend,t_align, nmax , npoints, model, error_str, fitnoise, l_int, index_mass,index_spin, error_type, error_val, af, mf,tau_var_str,nm_mock + return res \ No newline at end of file diff --git a/code_new/RD_Dynesty_Fits/build/lib/RD_Dynesty_Fits/test/__init__.py b/code_new/RD_Dynesty_Fits/build/lib/RD_Dynesty_Fits/test/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..8b137891791fe96927ad78e64b0aad7bded08bdc --- /dev/null +++ b/code_new/RD_Dynesty_Fits/build/lib/RD_Dynesty_Fits/test/__init__.py @@ -0,0 +1 @@ + diff --git a/code_new/RD_Dynesty_Fits/build/scripts-3.7/RD-Dynesty-Fits.py b/code_new/RD_Dynesty_Fits/build/scripts-3.7/RD-Dynesty-Fits.py new file mode 100755 index 0000000000000000000000000000000000000000..dafd9e25cef0b0f998d533d294618bffefbeae9a --- /dev/null +++ b/code_new/RD_Dynesty_Fits/build/scripts-3.7/RD-Dynesty-Fits.py @@ -0,0 +1,390 @@ +#!/work/francisco.jimenez/venv/bin/python +# coding: utf-8 + +# In[38]: + + +"""Generate ringdown templates in the time and perform parameter estimation on them. +""" + + +# In[1]: + + +#Import relevant modules, import data and all that +import time +import numpy as np +import corner +import matplotlib.pyplot as plt +from matplotlib.ticker import MaxNLocator +from matplotlib import rc +from configparser import ConfigParser +plt.rcParams.update({'font.size': 16.5}) + +from multiprocessing import Pool +import random +import dynesty +from dynesty import plotting as dyplot +from dynesty.utils import resample_equal +from dynesty import utils as dyfunc +import os +import argparse +import scipy.optimize as optimization +from scipy.optimize import minimize +import rdown as rd +import rdown_pe as rd_pe +import rdown_utilities as rd_ut +import read_data as rdata + + +# In[2]: + + +## Loading and running data tested with NR data +## Loading and running data tested with Mock data + + +# In[3]: + + +# Cell that calls the arguments from your 'config.ini' file. +try: + parser = argparse.ArgumentParser(description="Simple argument parser") + parser.add_argument("-c", action="store", dest="config_file") + result = parser.parse_args() + config_file=result.config_file + parser = ConfigParser() + parser.read(config_file) + parser.sections() +except SystemExit: + parser = ConfigParser() + parser.read('./run_0_mock/config_n0_to_1_mock.ini') + parser.sections() + pass + + +# In[4]: + + +# Load variables from config file +(simulation_path_1,simulation_path_2, metadata_file , simulation_number, output_folder, + export, overwrite, sampler,nr_code, nbcores,tshift,tend,t_align, + nmax , npoints, model, error_str, fitnoise, l_int, index_mass,index_spin, +error_type, error_val, af, mf,tau_var_str,nm_mock)=rdata.read_config_file(parser) + + +# In[5]: + + +# Show configuration options +dim = nmax+1 +ndim = 4*dim +numbins = 32 #corner plot parameter - how many bins you want + +print('model:',model) +print('nmax:',nmax) +print('nm_mock:',nm_mock) +print('tshift:',tshift) +print('error:', error_str) +print('error value:',error_val) +print('export:',export) +print('nr code:',nr_code) +print('fit noise:',fitnoise) + + +# In[6]: + + +# Create output directories +if not os.path.exists(output_folder): + os.mkdir(output_folder) + print("Directory " , output_folder , " Created ") + +if nr_code == 'Mock-data': + nm_mock_str = 'rec_with'+parser.get('rd-mock-parameters','nm_mock')+'_' +else: + nm_mock_str='' + +if error_str: + output_folder_1=(output_folder+'/'+model+'-nmax'+str(nmax)+'_'+nm_mock_str+str(error_str)+'_'+str(error_type)+'_fitnoise_'+str(fitnoise)) +else: + output_folder_1=output_folder+'/'+model+'-nmax'+str(nmax)+'_'+nm_mock_str+str(error_str)+'_'+'fitnoise_'+str(fitnoise) + +if not os.path.exists(output_folder_1): + os.mkdir(output_folder_1) + print("Directory " , output_folder_1 , " Created ") + + +# In[7]: + + +# Define output files +pars = [simulation_number,model,nmax,tshift,npoints] +corner_plot = rdata.create_output_files(output_folder_1,pars,'corner_plot') +corner_plot_extra = rdata.create_output_files(output_folder_1,pars,'corner_plot_extra') +diagnosis_plot = rdata.create_output_files(output_folder_1,pars,'diagnosis') +fit_plot = rdata.create_output_files(output_folder_1,pars,'fit') +samples_file = rdata.create_output_files(output_folder_1,pars,'post_samples') +results_file = rdata.create_output_files(output_folder_1,pars,'sampler_results') +sumary_data = rdata.create_output_files(output_folder_1,pars,'log_z') +best_data = rdata.create_output_files(output_folder_1,pars,'best_vals') + +files = [corner_plot,corner_plot_extra,diagnosis_plot,fit_plot,samples_file,results_file,sumary_data,best_data] + + +# In[8]: + + +# Remove old files if overwrite = True +if overwrite: + rd_ut.rm_files(files) + + +# In[46]: + + +#Load NR data, align in time and resize. Plot real part and amplitude. Finally compute the mismatch and the snr estimate +data = rdata.read_data(nr_code,simulation_path_1,RD=True,tshift=tshift,tend = tend,metadata_file=metadata_file,parser=parser) +data_l = rdata.read_data(nr_code,simulation_path_2,RD=True,tshift=tshift,tend = tend,metadata_file=metadata_file,parser=parser) +data_r, data_lr = rdata.nr_resize(data,data_l,tshift=tshift,tend=tend) +times_rd = data_r[:,0] + +plt.figure(figsize = (12, 8)) +plt.plot(times_rd, data_r[:,1].real, "r", alpha=0.3, lw=3, label=r'$Lev6$: real') +plt.plot(times_rd, np.sqrt((data_r[:,1].real)**2+(data_r[:,1].imag)**2), "r", alpha=0.3, lw=3, label=r'$Lev5\,amp$') +plt.plot(times_rd, data_lr[:,1].real, "b", alpha=0.3, lw=3, label=r'$Lev5: real$') +plt.plot(times_rd, np.sqrt((data_lr[:,1].real)**2+(data_lr[:,1].imag)**2), "b", alpha=0.3, lw=3, label=r'$Lev5\,amp$') +if error_str and error_val==0: + error = np.sqrt(data_r[:,1]*data_r[:,1]-2*data_r[:,1]*data_lr[:,1]+data_lr[:,1]*data_lr[:,1]) + error_est=np.sqrt(error.imag**2+error.real**2) + plt.plot(times_rd, error_est, "g", alpha=0.3, lw=2, label='error') +plt.legend() + +mismatch=1-rd_ut.EasyMatchT(times_rd,data_r[:,1],data_lr[:,1],tshift,tend) +error=np.sqrt(2*mismatch) +print('error estimate:',error) +print('mismatch:', mismatch) +print('snr:', rd_ut.EasySNRT(times_rd,data_r[:,1],data_lr[:,1],tshift,tend)/error**2) + + +# In[47]: + + +# Phase alignement +if parser.has_option('rd-model','phase_alignment'): + phase_alignment=eval(parser.get('rd-model','phase_alignment')) +else: + phase_alignment=False + +if phase_alignment: + datar_al = rdata.phase_align(data_r,data_lr) + gwdatanew5 = data_lr[:,1] + gwdatanew = datar_al[:,1] + timesrd_final = datar_al[:,0] + mismatch=1-rd_ut.EasyMatchT(timesrd_final,gwdatanew,gwdatanew5,tshift,tend) + error=np.sqrt(2*mismatch) + print('error estimate:',error) + print('mismatch:', mismatch) + print('snr:', rd_ut.EasySNRT(timesrd_final,gwdatanew,gwdatanew5,tshift,tend)/error) + if error_str: + error = np.sqrt(gwdatanew*gwdatanew-2*gwdatanew*gwdatanew5+gwdatanew5*gwdatanew5) + error_est=np.sqrt(error.imag**2+error.real**2) + else : + error = 1 +else: + datar_al = data_r + timesrd_final = datar_al[:,0] + +#Test the new interpolated data +if error_str and error_val==0: + plt.figure(figsize = (12, 8)) + plt.plot(timesrd_final, datar_al[:,1].real, "r", alpha=0.3, lw=2, label='Original') + plt.plot(timesrd_final, data_lr[:,1].real, "b", alpha=0.3, lw=2, label='Aligned') + plt.plot(timesrd_final, error_est, "b", alpha=0.3, lw=2, label='error') + plt.legend() + + +# In[48]: + + +# Define your noise depending on the noise configuration. Load priors and setup the likelihood with rd_pe.Ringdown_PE. +if error_str and error_val==0: + error_final = error_est + norm_factor = 100*len(error_final)/2*np.log(2*np.pi) +elif error_str and error_val!=0: + datar_al[:,1]+=random.uniform(0, error_val) + datar_al[:,1]+=1j*random.uniform(0, error_val) + error_tsh = error_val + error_final=(error_tsh.real**2+error_tsh.imag**2) + norm_factor = 0 +else: + error_tsh=1 + error_final=(error_tsh.real**2+error_tsh.imag**2) + norm_factor = 0 + +priors = rd_pe.load_priors(model,parser,nmax,fitnoise=fitnoise) +rdown=rd.Ringdown_Spectrum(mf,af,2,2,n=nmax,s=-2,time=timesrd_final) +rdown_pe = rd_pe.Ringdown_PE(rdown,datar_al,dim,priors,errors2=error_final,norm_factor=norm_factor,model=model,l_int=l_int) + + +# In[49]: + + +# Get a first estimate by trying to fit the data. +nll = lambda *args: -rdown_pe.log_likelihood(*args) +if model == 'w-tau-fixed-m-af': + if fitnoise: + initial = np.concatenate((np.ones(2*dim),[0.8,0.9,1])) + soln = minimize(nll, initial,bounds=priors) + vars_ml=soln.x + else: + initial = np.concatenate((np.ones(2*dim),[0.8,0.9])) + soln = minimize(nll, initial,bounds=priors) + vars_ml=soln.x +elif model == 'w-tau-fixed': + if fitnoise: + initial = np.concatenate((np.ones(2*dim),[0.2])) + soln = minimize(nll, initial,bounds=priors) + vars_ml=soln.x + else: + initial = np.ones(2*dim) + soln = minimize(nll, initial,bounds=priors) + vars_ml=soln.x +else: + if fitnoise: + initial = np.concatenate((np.ones(ndim),[1])) + soln = minimize(nll, initial,bounds=priors) + vars_ml=soln.x + else: + initial = np.ones(ndim) + soln = minimize(nll, initial,bounds=priors) + vars_ml=soln.x +print("best fit pars from fit: ",vars_ml) + + +# In[50]: + + +mypool = Pool(nbcores) +mypool.size = nbcores + +start = time.process_time() +f2=dynesty.NestedSampler(rdown_pe.log_likelihood,rdown_pe.prior_transform, len(priors), nlive=npoints,sample=sampler,pool=mypool) +if parser.has_option('setup','dlogz'): + dlogz=np.float(parser.get('setup','dlogz')) + f2.run_nested(dlogz=dlogz,print_progress=False) +else: + f2.run_nested(print_progress=False) + +print(time.process_time() - start) + + +# In[52]: + + +res = f2.results +res.samples_u.shape +res.summary() +samps=f2.results.samples +postsamps = rd_ut.posterior_samples(f2) +samps_tr=np.transpose(samps) +half_points=int(round((len(samps_tr[0])/1.25))) +evidence = res.logz[-1] +evidence_error = res.logzerr[-1] +if export: + rd_ut.save_object(res, results_file) + + +# In[53]: + + +pars = nmax,model,samps_tr, half_points +npamps = rd_ut.get_best_amps(pars,parser=parser,nr_code=nr_code) + + +# In[54]: + + +if export: + pars = simulation_number, nmax, tshift, evidence, evidence_error + rd_ut.export_logz_files(sumary_data,pars) + + +# In[55]: + + +labels = rd_ut.define_labels(dim,model,fitnoise) +if export: + pars = tshift, len(priors), labels + rd_ut.export_bestvals_files(best_data,postsamps,pars) + + +# In[56]: + + +w, tau = rdown.QNM_spectrum() +pars = w, tau, mf, af, npamps +truths = rd_ut.get_truths(model,pars,fitnoise) + + +# In[57]: + + +fg=corner.corner(postsamps,quantiles=[0.05,0.5,0.95],show_titles=True,max_n_ticks = 4,bins=50,truths=truths,labels=labels,truth_color='red') +plt.show() +if export: + fg.savefig(corner_plot, format = 'png', bbox_inches = 'tight') + + +# In[58]: + + +from importlib import reload +reload(rd_ut) +if model == 'w-tau-fixed-m-af' and export == True: + truths=np.concatenate((w,tau)) + labels_mf = np.concatenate((w_lab,tau_lab)) + new_samples = rd_ut.convert_m_af_2_w_tau_post(res,fitnoise=False) + figure = corner.corner(new_samples,truths=truths,quantiles=[0.05,0.95],labels=labels_mf,smooth=True,color='b',truth_color='r',show_titles=True) + figure.savefig(corner_plot_extra, format = 'png', bbox_inches = 'tight') + + +# In[151]: + + +#lnz_truth = ndim * -np.log(2 * 10.) # analytic evidence solution +fig, axes = dyplot.runplot(res) +fig.tight_layout() +if export: + fig.savefig(diagnosis_plot, format = 'png', dpi = 384, bbox_inches = 'tight') + + +# In[166]: + + +if export: + dict = {'w-tau':rdown.rd_model_wtau , 'w-q': rdown.rd_model_wq, 'w-tau-fixed':rdown.rd_model_wtau_fixed,'w-tau-fixed-m-af': rdown.rd_model_wtau_m_af} + figband = plt.figure(figsize = (12, 9)) + plt.plot(datar_al[:,0].real,datar_al[:,1].real, "green", alpha=0.9, lw=3, label=r'$res_{240}$') + onesig_bounds = np.array([np.percentile(postsamps[:, i], [5, 95]) for i in range(len(postsamps[0]))]).T + samples_1sigma = filter(lambda sample: np.all(onesig_bounds[0] <= sample) and np.all(sample <= onesig_bounds[1]), postsamps) + samples_1sigma_down = list(samples_1sigma)[::downfactor] + for sample in samples_1sigma_down: + plt.plot(datar_al[:,0].real, dict[model](sample).real, "r-", alpha=0.1, lw=1) + plt.title(r'Comparison of the MC fit data and the $1-\sigma$ error band') + plt.legend() + plt.xlabel('t') + plt.ylabel('h') + plt.show() + figband.savefig(fit_plot) + + +# In[162]: + + +if export: + with open(samples_file,'w') as file: + writer = csv.writer(file) + writer.writerow(labels) + writer.writerows(samps[::downfactor]) + diff --git a/code_new/RD_Dynesty_Fits/build/scripts-3.7/RD_Dynesty_Fits.py b/code_new/RD_Dynesty_Fits/build/scripts-3.7/RD_Dynesty_Fits.py new file mode 100755 index 0000000000000000000000000000000000000000..dafd9e25cef0b0f998d533d294618bffefbeae9a --- /dev/null +++ b/code_new/RD_Dynesty_Fits/build/scripts-3.7/RD_Dynesty_Fits.py @@ -0,0 +1,390 @@ +#!/work/francisco.jimenez/venv/bin/python +# coding: utf-8 + +# In[38]: + + +"""Generate ringdown templates in the time and perform parameter estimation on them. +""" + + +# In[1]: + + +#Import relevant modules, import data and all that +import time +import numpy as np +import corner +import matplotlib.pyplot as plt +from matplotlib.ticker import MaxNLocator +from matplotlib import rc +from configparser import ConfigParser +plt.rcParams.update({'font.size': 16.5}) + +from multiprocessing import Pool +import random +import dynesty +from dynesty import plotting as dyplot +from dynesty.utils import resample_equal +from dynesty import utils as dyfunc +import os +import argparse +import scipy.optimize as optimization +from scipy.optimize import minimize +import rdown as rd +import rdown_pe as rd_pe +import rdown_utilities as rd_ut +import read_data as rdata + + +# In[2]: + + +## Loading and running data tested with NR data +## Loading and running data tested with Mock data + + +# In[3]: + + +# Cell that calls the arguments from your 'config.ini' file. +try: + parser = argparse.ArgumentParser(description="Simple argument parser") + parser.add_argument("-c", action="store", dest="config_file") + result = parser.parse_args() + config_file=result.config_file + parser = ConfigParser() + parser.read(config_file) + parser.sections() +except SystemExit: + parser = ConfigParser() + parser.read('./run_0_mock/config_n0_to_1_mock.ini') + parser.sections() + pass + + +# In[4]: + + +# Load variables from config file +(simulation_path_1,simulation_path_2, metadata_file , simulation_number, output_folder, + export, overwrite, sampler,nr_code, nbcores,tshift,tend,t_align, + nmax , npoints, model, error_str, fitnoise, l_int, index_mass,index_spin, +error_type, error_val, af, mf,tau_var_str,nm_mock)=rdata.read_config_file(parser) + + +# In[5]: + + +# Show configuration options +dim = nmax+1 +ndim = 4*dim +numbins = 32 #corner plot parameter - how many bins you want + +print('model:',model) +print('nmax:',nmax) +print('nm_mock:',nm_mock) +print('tshift:',tshift) +print('error:', error_str) +print('error value:',error_val) +print('export:',export) +print('nr code:',nr_code) +print('fit noise:',fitnoise) + + +# In[6]: + + +# Create output directories +if not os.path.exists(output_folder): + os.mkdir(output_folder) + print("Directory " , output_folder , " Created ") + +if nr_code == 'Mock-data': + nm_mock_str = 'rec_with'+parser.get('rd-mock-parameters','nm_mock')+'_' +else: + nm_mock_str='' + +if error_str: + output_folder_1=(output_folder+'/'+model+'-nmax'+str(nmax)+'_'+nm_mock_str+str(error_str)+'_'+str(error_type)+'_fitnoise_'+str(fitnoise)) +else: + output_folder_1=output_folder+'/'+model+'-nmax'+str(nmax)+'_'+nm_mock_str+str(error_str)+'_'+'fitnoise_'+str(fitnoise) + +if not os.path.exists(output_folder_1): + os.mkdir(output_folder_1) + print("Directory " , output_folder_1 , " Created ") + + +# In[7]: + + +# Define output files +pars = [simulation_number,model,nmax,tshift,npoints] +corner_plot = rdata.create_output_files(output_folder_1,pars,'corner_plot') +corner_plot_extra = rdata.create_output_files(output_folder_1,pars,'corner_plot_extra') +diagnosis_plot = rdata.create_output_files(output_folder_1,pars,'diagnosis') +fit_plot = rdata.create_output_files(output_folder_1,pars,'fit') +samples_file = rdata.create_output_files(output_folder_1,pars,'post_samples') +results_file = rdata.create_output_files(output_folder_1,pars,'sampler_results') +sumary_data = rdata.create_output_files(output_folder_1,pars,'log_z') +best_data = rdata.create_output_files(output_folder_1,pars,'best_vals') + +files = [corner_plot,corner_plot_extra,diagnosis_plot,fit_plot,samples_file,results_file,sumary_data,best_data] + + +# In[8]: + + +# Remove old files if overwrite = True +if overwrite: + rd_ut.rm_files(files) + + +# In[46]: + + +#Load NR data, align in time and resize. Plot real part and amplitude. Finally compute the mismatch and the snr estimate +data = rdata.read_data(nr_code,simulation_path_1,RD=True,tshift=tshift,tend = tend,metadata_file=metadata_file,parser=parser) +data_l = rdata.read_data(nr_code,simulation_path_2,RD=True,tshift=tshift,tend = tend,metadata_file=metadata_file,parser=parser) +data_r, data_lr = rdata.nr_resize(data,data_l,tshift=tshift,tend=tend) +times_rd = data_r[:,0] + +plt.figure(figsize = (12, 8)) +plt.plot(times_rd, data_r[:,1].real, "r", alpha=0.3, lw=3, label=r'$Lev6$: real') +plt.plot(times_rd, np.sqrt((data_r[:,1].real)**2+(data_r[:,1].imag)**2), "r", alpha=0.3, lw=3, label=r'$Lev5\,amp$') +plt.plot(times_rd, data_lr[:,1].real, "b", alpha=0.3, lw=3, label=r'$Lev5: real$') +plt.plot(times_rd, np.sqrt((data_lr[:,1].real)**2+(data_lr[:,1].imag)**2), "b", alpha=0.3, lw=3, label=r'$Lev5\,amp$') +if error_str and error_val==0: + error = np.sqrt(data_r[:,1]*data_r[:,1]-2*data_r[:,1]*data_lr[:,1]+data_lr[:,1]*data_lr[:,1]) + error_est=np.sqrt(error.imag**2+error.real**2) + plt.plot(times_rd, error_est, "g", alpha=0.3, lw=2, label='error') +plt.legend() + +mismatch=1-rd_ut.EasyMatchT(times_rd,data_r[:,1],data_lr[:,1],tshift,tend) +error=np.sqrt(2*mismatch) +print('error estimate:',error) +print('mismatch:', mismatch) +print('snr:', rd_ut.EasySNRT(times_rd,data_r[:,1],data_lr[:,1],tshift,tend)/error**2) + + +# In[47]: + + +# Phase alignement +if parser.has_option('rd-model','phase_alignment'): + phase_alignment=eval(parser.get('rd-model','phase_alignment')) +else: + phase_alignment=False + +if phase_alignment: + datar_al = rdata.phase_align(data_r,data_lr) + gwdatanew5 = data_lr[:,1] + gwdatanew = datar_al[:,1] + timesrd_final = datar_al[:,0] + mismatch=1-rd_ut.EasyMatchT(timesrd_final,gwdatanew,gwdatanew5,tshift,tend) + error=np.sqrt(2*mismatch) + print('error estimate:',error) + print('mismatch:', mismatch) + print('snr:', rd_ut.EasySNRT(timesrd_final,gwdatanew,gwdatanew5,tshift,tend)/error) + if error_str: + error = np.sqrt(gwdatanew*gwdatanew-2*gwdatanew*gwdatanew5+gwdatanew5*gwdatanew5) + error_est=np.sqrt(error.imag**2+error.real**2) + else : + error = 1 +else: + datar_al = data_r + timesrd_final = datar_al[:,0] + +#Test the new interpolated data +if error_str and error_val==0: + plt.figure(figsize = (12, 8)) + plt.plot(timesrd_final, datar_al[:,1].real, "r", alpha=0.3, lw=2, label='Original') + plt.plot(timesrd_final, data_lr[:,1].real, "b", alpha=0.3, lw=2, label='Aligned') + plt.plot(timesrd_final, error_est, "b", alpha=0.3, lw=2, label='error') + plt.legend() + + +# In[48]: + + +# Define your noise depending on the noise configuration. Load priors and setup the likelihood with rd_pe.Ringdown_PE. +if error_str and error_val==0: + error_final = error_est + norm_factor = 100*len(error_final)/2*np.log(2*np.pi) +elif error_str and error_val!=0: + datar_al[:,1]+=random.uniform(0, error_val) + datar_al[:,1]+=1j*random.uniform(0, error_val) + error_tsh = error_val + error_final=(error_tsh.real**2+error_tsh.imag**2) + norm_factor = 0 +else: + error_tsh=1 + error_final=(error_tsh.real**2+error_tsh.imag**2) + norm_factor = 0 + +priors = rd_pe.load_priors(model,parser,nmax,fitnoise=fitnoise) +rdown=rd.Ringdown_Spectrum(mf,af,2,2,n=nmax,s=-2,time=timesrd_final) +rdown_pe = rd_pe.Ringdown_PE(rdown,datar_al,dim,priors,errors2=error_final,norm_factor=norm_factor,model=model,l_int=l_int) + + +# In[49]: + + +# Get a first estimate by trying to fit the data. +nll = lambda *args: -rdown_pe.log_likelihood(*args) +if model == 'w-tau-fixed-m-af': + if fitnoise: + initial = np.concatenate((np.ones(2*dim),[0.8,0.9,1])) + soln = minimize(nll, initial,bounds=priors) + vars_ml=soln.x + else: + initial = np.concatenate((np.ones(2*dim),[0.8,0.9])) + soln = minimize(nll, initial,bounds=priors) + vars_ml=soln.x +elif model == 'w-tau-fixed': + if fitnoise: + initial = np.concatenate((np.ones(2*dim),[0.2])) + soln = minimize(nll, initial,bounds=priors) + vars_ml=soln.x + else: + initial = np.ones(2*dim) + soln = minimize(nll, initial,bounds=priors) + vars_ml=soln.x +else: + if fitnoise: + initial = np.concatenate((np.ones(ndim),[1])) + soln = minimize(nll, initial,bounds=priors) + vars_ml=soln.x + else: + initial = np.ones(ndim) + soln = minimize(nll, initial,bounds=priors) + vars_ml=soln.x +print("best fit pars from fit: ",vars_ml) + + +# In[50]: + + +mypool = Pool(nbcores) +mypool.size = nbcores + +start = time.process_time() +f2=dynesty.NestedSampler(rdown_pe.log_likelihood,rdown_pe.prior_transform, len(priors), nlive=npoints,sample=sampler,pool=mypool) +if parser.has_option('setup','dlogz'): + dlogz=np.float(parser.get('setup','dlogz')) + f2.run_nested(dlogz=dlogz,print_progress=False) +else: + f2.run_nested(print_progress=False) + +print(time.process_time() - start) + + +# In[52]: + + +res = f2.results +res.samples_u.shape +res.summary() +samps=f2.results.samples +postsamps = rd_ut.posterior_samples(f2) +samps_tr=np.transpose(samps) +half_points=int(round((len(samps_tr[0])/1.25))) +evidence = res.logz[-1] +evidence_error = res.logzerr[-1] +if export: + rd_ut.save_object(res, results_file) + + +# In[53]: + + +pars = nmax,model,samps_tr, half_points +npamps = rd_ut.get_best_amps(pars,parser=parser,nr_code=nr_code) + + +# In[54]: + + +if export: + pars = simulation_number, nmax, tshift, evidence, evidence_error + rd_ut.export_logz_files(sumary_data,pars) + + +# In[55]: + + +labels = rd_ut.define_labels(dim,model,fitnoise) +if export: + pars = tshift, len(priors), labels + rd_ut.export_bestvals_files(best_data,postsamps,pars) + + +# In[56]: + + +w, tau = rdown.QNM_spectrum() +pars = w, tau, mf, af, npamps +truths = rd_ut.get_truths(model,pars,fitnoise) + + +# In[57]: + + +fg=corner.corner(postsamps,quantiles=[0.05,0.5,0.95],show_titles=True,max_n_ticks = 4,bins=50,truths=truths,labels=labels,truth_color='red') +plt.show() +if export: + fg.savefig(corner_plot, format = 'png', bbox_inches = 'tight') + + +# In[58]: + + +from importlib import reload +reload(rd_ut) +if model == 'w-tau-fixed-m-af' and export == True: + truths=np.concatenate((w,tau)) + labels_mf = np.concatenate((w_lab,tau_lab)) + new_samples = rd_ut.convert_m_af_2_w_tau_post(res,fitnoise=False) + figure = corner.corner(new_samples,truths=truths,quantiles=[0.05,0.95],labels=labels_mf,smooth=True,color='b',truth_color='r',show_titles=True) + figure.savefig(corner_plot_extra, format = 'png', bbox_inches = 'tight') + + +# In[151]: + + +#lnz_truth = ndim * -np.log(2 * 10.) # analytic evidence solution +fig, axes = dyplot.runplot(res) +fig.tight_layout() +if export: + fig.savefig(diagnosis_plot, format = 'png', dpi = 384, bbox_inches = 'tight') + + +# In[166]: + + +if export: + dict = {'w-tau':rdown.rd_model_wtau , 'w-q': rdown.rd_model_wq, 'w-tau-fixed':rdown.rd_model_wtau_fixed,'w-tau-fixed-m-af': rdown.rd_model_wtau_m_af} + figband = plt.figure(figsize = (12, 9)) + plt.plot(datar_al[:,0].real,datar_al[:,1].real, "green", alpha=0.9, lw=3, label=r'$res_{240}$') + onesig_bounds = np.array([np.percentile(postsamps[:, i], [5, 95]) for i in range(len(postsamps[0]))]).T + samples_1sigma = filter(lambda sample: np.all(onesig_bounds[0] <= sample) and np.all(sample <= onesig_bounds[1]), postsamps) + samples_1sigma_down = list(samples_1sigma)[::downfactor] + for sample in samples_1sigma_down: + plt.plot(datar_al[:,0].real, dict[model](sample).real, "r-", alpha=0.1, lw=1) + plt.title(r'Comparison of the MC fit data and the $1-\sigma$ error band') + plt.legend() + plt.xlabel('t') + plt.ylabel('h') + plt.show() + figband.savefig(fit_plot) + + +# In[162]: + + +if export: + with open(samples_file,'w') as file: + writer = csv.writer(file) + writer.writerow(labels) + writer.writerows(samps[::downfactor]) + diff --git a/code_new/RD_Dynesty_Fits/build/scripts-3.7/rdown.py b/code_new/RD_Dynesty_Fits/build/scripts-3.7/rdown.py new file mode 100755 index 0000000000000000000000000000000000000000..1357ccbf98a454670c79fb49574d7fe1447e243a --- /dev/null +++ b/code_new/RD_Dynesty_Fits/build/scripts-3.7/rdown.py @@ -0,0 +1,208 @@ +# Copyright (C) 2021 Xisco Jimenez Forteza +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + +# +# ============================================================================= +# +# Preamble +# +# ============================================================================= +# +# Module to generate RD waveforms. + +import numpy as np +import qnm +import os + +f_fpars= [[2.95845, -2.58697, 0.0533469], [2.12539, -1.78054, 0.0865503], [1.74755, -1.44776, 0.123666], [1.78287, -1.53203, 0.129475], [2.04028, -1.83224, 0.112497]] +q_fpars=[[0.584077, 1.52053, -0.480658], [0.00561441, 0.630715, -0.432664], [-0.197965, 0.515956, -0.369706], [-0.275097, 0.455691, -0.331543], [-0.287596, 0.398514, -0.309799]] + + +c=2.99792458*10**8;G=6.67259*10**(-11);MS=1.9885*10**30; +class Ringdown_Spectrum: + """RDown model generator""" + def __init__(self,mf,af,l,m,n=4,s=-2,time=[],fixed=False,qnm_model='berti'): + self.mf = mf + self.af = af + self.l = l + self.m = m + self.n = n + self.time = time + self.grav_220 = [qnm.modes_cache(s=s,l=self.l,m=self.m,n=i) for i in range (0,self.n+1)] + self.dim = self.n+1 + self.fixed = fixed + self.qnm_model = qnm_model + dict_omega = {'berti': self.QNM_Berti , 'qnm': self.QNM_spectrum} + dic = {'w-tau':self.rd_model_wtau , 'w-q': self.rd_model_wq, 'w-tau-fixed':self.rd_model_wtau_fixed,'w-tau-fixed-m-af': self.rd_model_wtau_m_af} + + if len(self.time)==0: + self.time = np.arange(0,100,0.1) + + if self.fixed: + omegas_new=np.asarray([self.grav_220[i](a=self.af)[0] for i in range (0,self.dim)]) + self.w = (np.real(omegas_new))/self.mf + self.tau=-1/(np.imag(omegas_new))*self.mf + + + def QNM_spectrum(self): + """ It computes the RD frequencies and damping times in NR units. + """ + omegas_new=np.asarray([self.grav_220[i](a=self.af)[0] for i in range (0,self.n+1)]) + w_m_a = (np.real(omegas_new))/self.mf + tau_m_a=-1/(np.imag(omegas_new))*self.mf + + return (w_m_a, tau_m_a) + + def QNM_Berti(self,rdowndata): + """ It computes the RD frequencies and damping times in NR units. + """ + position=np.argmax(rdowndata[0,0] >= (self.af)) + #w_m_a=f1+f2*(1-af)**f3 + w_m_a=[None]*(self.n+1) + tau_ma_a=[None]*(self.n+1) + + for i in range(self.n+1): + qnm=rdowndata[i,1:3,position] + w_m_a[i] = qnm[0]/self.mf + tau_ma_a[i] = -1/(qnm[1])*self.mf + + return w_m_a, tau_ma_a + + + def w_fpars_Berti(self,n): + return f_fpars[n] + + def tau_qpars_Berti(self,n): + return q_fpars[n] + + def mass_from_wtau(self,n,w,tau): + f1,f2,f3 = w_fpars_Berti(n) + q1,q2,q3 = tau_qpars_Berti(n) + res=(f1 + f2*(2**(-1/q3)*((-2*q1 + w*tau)/q2)**(1/q3))**f3)/w + return res + + def spin_from_wtau(self,n,w,tau): + f1,f2,f3 = w_fpars_Berti(n) + q1,q2,q3 = tau_qpars_Berti(n) + res=1 - 2**(-1/q3)*((-2*q1 + w*tau)/q2)**(1/q3) + return res + + def mass_from_wtau_loop(self,w,tau,l,m): + res=[None]*dim + for n in range (0,dim): + f1,f2,f3 = w_fpars_Berti(n) + q1,q2,q3 = tau_qpars_Berti(n) + res[n]=(f1 + f2*(2**(-1/q3)*((-2*q1 + w[n]*tau[n])/q2)**(1/q3))**f3)/w[n] + return res + + def spin_from_wtau_loop(self,w,tau,l,m): + res=[None]*dim + for n in range (0,dim): + f1,f2,f3 = w_fpars_Berti(n) + q1,q2,q3 = tau_qpars_Berti(n) + res[n]= 1 - 2**(-1/q3)*((-2*q1 + w[n]*tau[n])/q2)**(1/q3) + return res + + + def rd_model_wtau(self,theta): + """RD model parametrized with the damping time tau. + """ + assert int(len(theta)/4) == self.dim, 'Please recheck your n and parameters' + + wvars = theta[ : (self.dim)] + tvars = theta[(self.dim) : 2*(self.dim)] + xvars = theta[2*(self.dim) : 3*(self.dim)] + yvars = theta[3*(self.dim) : ] + + ansatz = 0 + for i in range (0,self.dim): + ansatz += (xvars[i]*np.exp(1j*yvars[i]))*np.exp(-self.time/tvars[i]) * (np.cos(wvars[i]*self.time)-1j*np.sin(wvars[i]*self.time)) + # -1j to agree with SXS convention + return ansatz + + def rd_model_wtau_m_af(theta): + """RD model parametrized with the damping time tau and with the QNM spectrum fixd to GR. The QNM spectrum is given from the mass and spin. + """ + xvars = theta[ : (dim)] + yvars = theta[(dim) : 2*(dim)] + mass_vars = theta[index_mass] + spin_vars = theta[index_spin] + + w_m_a , tau_m_a = dict_omega[self.qnm_model](mass_vars,spin_vars,2,2) + + ansatz = 0 + for i in range (0,dim): + ansatz += (xvars[i]*np.exp(1j*yvars[i]))*np.exp(-timesrd_final_tsh/tau_m_a[i]) * (np.cos(w_m_a[i]*timesrd_final_tsh)-1j*np.sin(w_m_a[i]*timesrd_final_tsh)) + # -1j to agree with SXS convention + return ansatz + + def rd_model_wtau_fixed(theta): + """RD model parametrized with the damping time tau and with the QNM spectrum fixd to GR. + """ + xvars = theta[ : (dim)] + yvars = theta[(dim) : 2*(dim)] + + ansatz = 0 + for i in range (0,dim): + ansatz += (xvars[i]*np.exp(1j*yvars[i]))*np.exp(-timesrd_final_tsh/tau[i]) * (np.cos(w[i]*timesrd_final_tsh)-1j*np.sin(w[i]*timesrd_final_tsh)) + # -1j to agree with SXS convention + return ansatz + + def rd_model_wq(self,theta): + """RD model parametrized with the quality factor q. + """ + assert int(len(theta)/4) == self.dim, 'Please recheck your n and parameters' + + wvars = theta[ : (self.dim)] + qvars = theta[(self.dim) : 2*(self.dim)] + xvars = theta[2*(self.dim) : 3*(self.dim)] + yvars = theta[3*(self.dim) : ] + + ansatz = 0 + for i in range (0,self.dim): + ansatz += (xvars[i]*np.exp(1j*yvars[i]))*np.exp(-self.time*np.pi*wvars[i]/qvars[i])*(np.cos(wvars[i]*self.time)-1j*np.sin(wvars[i]*self.time)) + # -1j to agree with SXS convention + return ansatz + + def rd_model_wq_fixed(self,theta): + """RD model parametrized with the damping time tau and with the QNM spectrum fixd to GR. + """ + xvars = theta[ : (self.dim)] + yvars = theta[(self.dim) : 2*(self.dim)] + + ansatz = 0 + for i in range (0,self.dim): + ansatz += (xvars[i]*np.exp(1j*yvars[i]))*np.exp(-self.time/self.tau[i]) * (np.cos(self.w[i]*self.time)-1j*np.sin(self.w[i]*self.time)) + # -1j to agree with SXS convention + return ansatz + + + def rd_model_wq_m_a(self,theta): + """RD model parametrized with the damping time tau and with the QNM spectrum fixd to GR. The QNM spectrum is given from the mass and spin. + """ + xvars = theta[ : (self.dim)] + yvars = theta[(self.dim) : 2*(self.dim)] + mass_vars = theta[-2] + spin_vars = theta[-1] + + w_m_a , tau_m_a = QNM_spectrum() + + ansatz = 0 + for i in range (0,dim): + ansatz += (xvars[i]*np.exp(1j*yvars[i]))*np.exp(-timesrd_final_tsh/tau_m_a[i]) * (np.cos(w_m_a[i]*timesrd_final_tsh)-1j*np.sin(w_m_a[i]*timesrd_final_tsh)) + # -1j to agree with SXS convention + return ansatz \ No newline at end of file diff --git a/code_new/RD_Dynesty_Fits/build/scripts-3.7/rdown_pe.py b/code_new/RD_Dynesty_Fits/build/scripts-3.7/rdown_pe.py new file mode 100755 index 0000000000000000000000000000000000000000..c92e073cac48d68b9fb46fc44a03b6e1c2c8af65 --- /dev/null +++ b/code_new/RD_Dynesty_Fits/build/scripts-3.7/rdown_pe.py @@ -0,0 +1,191 @@ +# Copyright (C) 2021 Xisco Jimenez Forteza +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + +# +# ============================================================================= +# +# Preamble +# +# ============================================================================= +# +# Module to run PE on RD data +import random +from multiprocessing import Pool +import dynesty +import numpy as np +import rdown + +class Ringdown_PE: + def __init__(self,rdown_fun,data,dim,priors,errors2=1,theta=[],model='w-tau',norm_factor=0,l_int=0): + self.dim = dim + self.rdown_fun = rdown_fun + self.times = data[:,0] + self.datare = data[:,1].real + self.dataim = data[:,1].imag + self.priors = priors + self.priors_min = priors[:,0] + self.priors_max = priors[:,1] + self.prior_dim = len(priors) + self.errors2 = errors2 + self.norm_factor = norm_factor + self.model = model + self.l_int = l_int + self.theta = theta + self.dict = {'w-tau':rdown_fun.rd_model_wtau , 'w-q': rdown_fun.rd_model_wq, 'w-tau-fixed':rdown_fun.rd_model_wtau_fixed,'w-tau-fixed-m-af': rdown_fun.rd_model_wtau_m_af} + + #def log_likelihood(self,theta,sigma=1): + # """chi2 likelihood. + # """ + # modelev = dict[model](theta) + # result = -np.sum(((gwdatanew_re_tsh - modelev.real)**2+(gwdatanew_im_tsh - modelev.imag)**2)/(2*theta[-1]*error_final)) + # if np.isnan(result): + # return -np.inf + # return result + + def log_likelihood(self,theta,sigma=1): + """chi2 likelihood. + """ + modelev = self.dict[self.model](theta) + modelevre= modelev.real + modelevim= modelev.imag + + sigma2 = self.errors2 + self.l_int*(self.datare** 2+self.dataim**2) * np.exp(2 * theta[-1]) + + result = -0.5*np.sum(((self.datare - modelevre)**2+(self.dataim - modelevim)**2)/sigma2+self.l_int*(np.log(2*np.pi*sigma2)))-self.l_int*self.norm_factor + + if np.isnan(result): + return -np.inf + return result + + + def prior_transform(self,cube): + """RD uniform priors. The values for priors_min and priors_max must be given out of this function. + """ + for i in range(self.prior_dim): + cube[i] = self.priors_min[i]+ cube[i]*(self.priors_max[i]-self.priors_min[i]) + return cube + +def load_priors(model,config_parser,nmax,fitnoise=True): + # loading priors + if model == 'w-q': + tau_var_str='q' + else: + tau_var_str='tau' + + if model == 'w-tau': + w_mins=np.empty(nmax+1) + w_maxs=np.empty(nmax+1) + tau_mins=np.empty(nmax+1) + tau_maxs=np.empty(nmax+1) + a_mins=np.empty(nmax+1) + a_maxs=np.empty(nmax+1) + ph_mins=np.empty(nmax+1) + ph_maxs=np.empty(nmax+1) + + for i in range(nmax+1): + wp_min=config_parser.get('prior-w'+str(i),'w'+str(i)+'_min') + w_mins[i] = np.float(wp_min) + + wp_max=config_parser.get('prior-w'+str(i),'w'+str(i)+'_max') + w_maxs[i] = np.float(wp_max) + + taup_min=config_parser.get('prior-'+tau_var_str+str(i),tau_var_str+str(i)+'_min') + tau_mins[i] = np.float(taup_min) + + taup_max=config_parser.get('prior-'+tau_var_str+str(i),tau_var_str+str(i)+'_max') + tau_maxs[i] = np.float(taup_max) + + amp0_min=config_parser.get('prior-amp'+str(i),'amp'+str(i)+'_min') + a_mins[i] = np.float(amp0_min) + + amp1_max=config_parser.get('prior-amp'+str(i),'amp'+str(i)+'_max') + a_maxs[i] = np.float(amp1_max) + + phase_min=config_parser.get('prior-phase'+str(i),'phase'+str(i)+'_min') + ph_mins[i] = np.float(phase_min)*2*np.pi + + phase_max=config_parser.get('prior-phase'+str(i),'phase'+str(i)+'_max') + ph_maxs[i] = np.float(phase_max)*2*np.pi + + priors_min = np.concatenate((w_mins,tau_mins,a_mins,ph_mins)) + priors_max = np.concatenate((w_maxs,tau_maxs,a_maxs,ph_maxs)) + prior_dim = len(priors_min) + priors=np.column_stack((priors_min,priors_max)) + + if model == 'w-tau-fixed': + a_mins=np.empty(nmax+1) + a_maxs=np.empty(nmax+1) + ph_mins=np.empty(nmax+1) + ph_maxs=np.empty(nmax+1) + + for i in range(nmax+1): + amp0_min=config_parser.get('prior-amp'+str(i),'amp'+str(i)+'_min') + a_mins[i] = np.float(amp0_min) + + amp1_max=config_parser.get('prior-amp'+str(i),'amp'+str(i)+'_max') + a_maxs[i] = np.float(amp1_max) + + phase_min=config_parser.get('prior-phase'+str(i),'phase'+str(i)+'_min') + ph_mins[i] = np.float(phase_min)*2*np.pi + + phase_max=config_parser.get('prior-phase'+str(i),'phase'+str(i)+'_max') + ph_maxs[i] = np.float(phase_max)*2*np.pi + + + priors_min = np.concatenate((a_mins,ph_mins)) + priors_max = np.concatenate((a_maxs,ph_maxs)) + prior_dim = len(priors_min) + priors=np.column_stack((priors_min,priors_max)) + + elif model == 'w-tau-fixed-m-af': + a_mins=np.empty(nmax+1) + a_maxs=np.empty(nmax+1) + ph_mins=np.empty(nmax+1) + ph_maxs=np.empty(nmax+1) + + for i in range(nmax+1): + amp0_min=config_parser.get('prior-amp'+str(i),'amp'+str(i)+'_min') + a_mins[i] = np.float(amp0_min) + + amp1_max=config_parser.get('prior-amp'+str(i),'amp'+str(i)+'_max') + a_maxs[i] = np.float(amp1_max) + + phase_min=config_parser.get('prior-phase'+str(i),'phase'+str(i)+'_min') + ph_mins[i] = np.float(phase_min)*2*np.pi + + phase_max=config_parser.get('prior-phase'+str(i),'phase'+str(i)+'_max') + ph_maxs[i] = np.float(phase_max)*2*np.pi + + mass_min=[np.float(config_parser.get('prior-mass','mass_min'))] + mass_max=[np.float(config_parser.get('prior-mass','mass_max'))] + spin_min=[np.float(config_parser.get('prior-spin','spin_min'))] + spin_max=[np.float(config_parser.get('prior-spin','spin_max'))] + priors_min = np.concatenate((a_mins,ph_mins,mass_min,spin_min)) + priors_max = np.concatenate((a_maxs,ph_maxs,mass_max,spin_max)) + prior_dim = len(priors_min) + priors=np.column_stack((priors_min,priors_max)) + + + if fitnoise: + priors_fit_min=[np.float(config_parser.get('prior-noise','noise_min'))] + priors_fit_max=[np.float(config_parser.get('prior-noise','noise_max'))] + priors_min = np.concatenate((priors_min,priors_fit_min)) + priors_max = np.concatenate((priors_max,priors_fit_max)) + priors=np.column_stack((priors_min,priors_max)) + prior_dim = len(priors_min) + + return priors \ No newline at end of file diff --git a/code_new/RD_Dynesty_Fits/build/scripts-3.7/rdown_utilities.py b/code_new/RD_Dynesty_Fits/build/scripts-3.7/rdown_utilities.py new file mode 100755 index 0000000000000000000000000000000000000000..c4a5b95c1c26beb418d2457fbd2a2b09212778c3 --- /dev/null +++ b/code_new/RD_Dynesty_Fits/build/scripts-3.7/rdown_utilities.py @@ -0,0 +1,318 @@ +# Copyright (C) 2021 Xisco Jimenez Forteza +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + +# +# ============================================================================= +# +# Preamble +# +# ============================================================================= +# +# Module to run PE on RD data +import numpy as np +from dynesty.utils import resample_equal +from dynesty import utils as dyfunc +import os +import csv +import pandas as pd +import pickle + +def posterior_samples(sampler): + """ + Returns posterior samples from nested samples and weights + given by dynsety sampler + """ + + dynesty_samples = sampler.results['samples'] + wt = np.exp(sampler.results['logwt'] - + sampler.results['logz'][-1]) + # Make sure that sum of weights equal to 1 + weights = wt/np.sum(wt) + posterior_dynesty = dyfunc.resample_equal(dynesty_samples, weights) + return posterior_dynesty + +def FFT_FreqBins(times): + Len = len(times) + DeltaT = times[-1]- times[0] + dt = DeltaT/(Len-1) + dnu = 1/(Len*dt) + maxfreq = 1/(2*dt) + add = dnu/4 + + p = np.arange(0.0,maxfreq+add,dnu) + m = np.arange(p[-1]-(2*maxfreq)+dnu,-dnu/2+add,dnu) + res=np.concatenate((p,m)) + + return res + +def hFromPsi4FFI(tpsi4,f0): + + timecheck1=tpsi4[-2,0]-tpsi4[-1,0] + timecheck2=tpsi4[1,0]-tpsi4[0,0] + + if np.abs(timecheck1-timecheck2)>=0.0001: + print("The data might not be equally sampled!!") + + times,data= tpsi4[:,0],tpsi4[:,1] + + freqs = FT_FreqBins(xaxis.real).real + position = np.argmax(freqs >= f0) + freqs[:position]=f0*np.ones(len(freqs[:position])) + freqs=2*np.pi*freqs + + fdata=fft(data) + len(myTable)*ifft(- fdata/floor**2); + np.stack((times,data)).T + + +def twopoint_autocovariance(t,n): + """ It computes the two-point autocovariance function. + """ + dt=t[1]-t[0] + res = np.zeros(len(n)) + taus = np.zeros(len(n)) + for tau in range(0,int(len(n)/2)): + ntau=np.roll(n, tau) + taus[tau] = t[tau] + res[tau]=np.sum(n*ntau).real + return (taus[:int(len(n)/2)],res[:int(len(n)/2)]) + +def save_object(obj, filename): + with open(filename, 'wb') as output: # Overwrites any existing file. + pickle.dump(obj, output, pickle.HIGHEST_PROTOCOL) + + +def EasyMatchT(t,h1,h2,tmin,tmax): + """ It computes the time-domain match for (h1|h2) complex waveforms. + """ + pos = np.argmax(t >= (tmin)); + + h1red=h1[pos:]; + h2red=h2[pos:]; + + norm1=np.sum(np.abs(h1red)**2) + norm2=np.sum(np.abs(h2red)**2) + + myTable=h1red*np.conjugate(h2red) + res=((np.sum(myTable)/np.sqrt(norm1*norm2))).real + + return res + +def EasySNRT(t,h1,h2,tmin,tmax): + """ It computes the time-domain snr for (h1|h2) complex waveforms. + """ + pos = np.argmax(t >= (tmin)); + + h1red=h1[pos:]; + h2red=h2[pos:]; + + myTable=h1red*np.conjugate(h2red) + res=2*np.sqrt((np.sum(myTable)).real) + + return res + +def FindTmaximum(y): + """ It determines the maximum absolute value of the complex waveform. + """ + absval = np.sqrt(y[:,1]*y[:,1]+y[:,2]*y[:,2]) + vmax=np.max(absval) + index = np.argmax(absval == vmax) + timemax=y[index,0] + + return timemax + +def export_logz_files(output_file,pars): + sim_num, nmax, tshift, evidence, evidence_error = pars + + """ + Generate the logz.csv files you want to export the data to. + file_type must be one of this options: [corner_plot,corner_plot_extra,diagnosis,fit,post_samples,sampler_results,log_z] + """ + + summary_titles=['n','id','t_shift','dlogz','dlogz_err'] + if os.path.exists(output_file): + outvalues = np.array([[nmax, sim_num, tshift, evidence,evidence_error]]) + else: + outvalues = np.array([summary_titles,[nmax, sim_num, tshift, evidence,evidence_error]]) + + with open(output_file, 'a') as file: + writer = csv.writer(file) + if (outvalues.shape)[0]>1 : + writer.writerows(outvalues) + else: + writer.writerow(outvalues[0]) + + return + +def export_bestvals_files(best_data_file,postsamps,pars): + + tshift, lenpriors, labels = pars + + sigma_vars_m = np.empty(lenpriors) + sigma_vars_p = np.empty(lenpriors) + sigma_vars = np.empty(lenpriors) + sigma_vars_ml = np.empty(lenpriors) + for i in range(lenpriors): + amps_aux = postsamps[:,i] + sigma_vars_m[i] = np.quantile(amps_aux, 0.05) + sigma_vars[i] = np.quantile(amps_aux, 0.5) + sigma_vars_ml[i] = postsamps[-1,i] + sigma_vars_p[i] = np.quantile(amps_aux, 0.95) + + sigma_vars_all = [sigma_vars,sigma_vars_ml,sigma_vars_m,sigma_vars_p] + sigma_vars_all=np.stack([sigma_vars,sigma_vars_ml,sigma_vars_m,sigma_vars_p], axis=0) + + key =['max val','max val ml','lower bound','higher bound'] + dfslist = [pd.DataFrame(np.concatenate(([tshift],sigma_vars_all[i])).reshape((-1,lenpriors+1)), columns=np.concatenate((['tshift'],labels)), index = [key[i]]) for i in range(4)] + df2 = pd.concat(dfslist) + if os.path.exists(best_data_file): + df2.to_csv(best_data_file, mode='a', header=False,index = True) + else: + df2.to_csv(best_data_file, index = True) + + + +def define_labels(dim,model,fitnoise): + wstr = r'$\omega_' + + if model == 'w-tau': + taustr = r'$\tau_' + elif model == 'w-q': + taustr = r'$q_' + elif model == 'w-tau-fixed': + taustr = r'$dumb_var}' + elif model == 'w-tau-fixed-m-af': + taustr = r'$\tau_' + + ampstr = r'$A_' + phasestr = r'$\phi_' + + w_lab = [None] * dim + tau_lab = [None] * dim + amp_lab = [None] * dim + pha_lab = [None] * dim + mass_lab = ['mass'] + spin_lab = ['spin'] + + for i in range(dim): + w_lab[i] = wstr+str(i)+'$' + tau_lab[i] = taustr+str(i)+'$' + amp_lab[i] = ampstr+str(i)+'$' + pha_lab[i] = phasestr+str(i)+'$' + + + labels = np.concatenate((w_lab,tau_lab,amp_lab,pha_lab)) + + if model=='w-tau-fixed': + labels = np.concatenate((amp_lab,pha_lab)) + + if model=='w-tau-fixed-m-af': + pha_lab[i] = phasestr+str(i)+'$' + + labels = np.concatenate((amp_lab,pha_lab,mass_lab,spin_lab)) + + if fitnoise: + noise_lab = ['noise'] + labels = np.concatenate((labels,noise_lab)) + + return labels + +def get_truths(model,pars,fitnoise): + w, tau, mf, af , npamps = pars + if model == 'w-q': + tau_val = np.pi*w*tau + truths = np.concatenate((w,tau_val,npamps)) + elif model == 'w-tau': + tau_val = tau + truths = np.concatenate((w,tau_val,npamps)) + elif model == 'w-tau-fixed': + truths = npamps + elif model == 'w-tau-fixed-m-af': + truths = np.concatenate((npamps,[mf],[af])) + + if fitnoise: + truths = np.concatenate((truths,[1])) + + return truths + +def get_best_amps(pars,parser=None,nr_code=None): + nmax,model,samps_tr,half_points = pars + + + if model=='w-tau-fixed': + rg = (nmax+1) + elif model=='w-tau-fixed': + rg = (nmax+1)+2 + else: + rg = (nmax+1)*2 + + + if model=='w-tau-fixed-a-mf': + npamps = np.empty((nmax+1)) + for i in range(0,(nmax+1)): + amps_aux = samps_tr[i+rg][half_points:-1] + npamps[i] = np.quantile(amps_aux, 0.5) + else : + npamps = np.empty((nmax+1)*2) + for i in range(0,(nmax+1)*2): + amps_aux = samps_tr[i][half_points:-1] + npamps[i] = np.quantile(amps_aux, 0.5) + + if nr_code == 'Mock-data': + nm_mock = parser.get('rd-mock-parameters','nm_mock') + nm_mock = np.int(nm_mock) + amp_mock=np.empty(nm_mock+1) + ph_mock=np.empty(nm_mock+1) + for i in range(nm_mock+1): + amp_mockp = parser.get('rd-mock-parameters','amp'+str(i)) + amp_mock[i] = np.float(amp_mockp) + ph_mockp=parser.get('rd-mock-parameters','phase'+str(i)) + ph_mock[i] = np.float(ph_mockp) + + npamps = np.concatenate((amp_mock,ph_mock)) + return npamps + +def convert_m_af_2_w_tau_post(res,fitnoise=False): + + samples_2=res.samples + samps=f2.results.samples + + if fitnoise: + fmass_spin=(samps.T)[-3:-1].T + else: + fmass_spin=(samps.T)[-2:].T + #fmass_spin=new_samples[-2:] + fmass_spin_dist=[None]*len(fmass_spin) + weight=np.exp(res.logwt - res.logz[-1]) + for i in range(len(fmass_spin)): + fmass_spin_dist[i]=np.concatenate(dict_omega[qnm_model](fmass_spin[i,0],fmass_spin[i,1],2,2)) + + fmass_spin_dist_v2=np.asarray(fmass_spin_dist) + new_samples = dyfunc.resample_equal(fmass_spin_dist_v2, weight) + + return new_samples + +def save_object(obj, filename): + with open(filename, 'wb') as output: # Overwrites any existing file. + pickle.dump(obj, output, pickle.HIGHEST_PROTOCOL) + +def rm_files(files): + """ rm all old files """ + for i in files: + if os.path.exists(i): + os.remove(i) + \ No newline at end of file diff --git a/code_new/RD_Dynesty_Fits/build/scripts-3.7/read_data.py b/code_new/RD_Dynesty_Fits/build/scripts-3.7/read_data.py new file mode 100755 index 0000000000000000000000000000000000000000..87185de6364a1b89cb9223329e31dc5bb3e58391 --- /dev/null +++ b/code_new/RD_Dynesty_Fits/build/scripts-3.7/read_data.py @@ -0,0 +1,344 @@ +# Copyright (C) 2021 Xisco Jimenez Forteza +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + +# +# ============================================================================= +# +# Preamble +# +# ============================================================================= +# +# Module to run PE on RD data +import numpy as np +import rdown_utilities as rd_ut +import romspline +import rdown as rd +import h5py +import json +from scipy import interpolate +from scipy.interpolate import interp1d + + +def read_data(nr_code,sim_path,mf=1,af=0,parser=None,RD=True,tshift=0,tend = 100,metadata_file=None): + if nr_code=='SXS': + gw = {} + gw = h5py.File(sim_path, 'r') + gw_data = gw["Extrapolated_N3.dir"]["Y_l2_m2.dat"] + times = gw_data[:,0] + + metadata = {} + with open(metadata_file) as file: + metadata = json.load(file) + + af = metadata['remnant_dimensionless_spin'][-1] + mf = metadata['remnant_mass'] + + tmax=rd_ut.FindTmaximum(gw_data[round(len(gw_data)/2):]) + times = times - tmax + + if RD: + position = np.argmax(times >= 0) + gw_data = gw_data[:,1][position:]+1j*gw_data[:,2][position:] + times = times[times >= 0] + + elif nr_code=='Maya': + dt=0.1 + gw = {} + gw = h5py.File(sim_path, 'r') + gw_sxs_bbh_0305_amp = np.asarray(gw['amp_l2_m2/Y'])[6:] + times_1 = np.asarray(gw['amp_l2_m2/X'])[6:] + gw_sxs_bbh_0305_amp_int = romspline.ReducedOrderSpline(times_1, gw_sxs_bbh_0305_amp) + gw_sxs_bbh_0305_pha = np.asarray(gw['phase_l2_m2/Y'])[6:] + times = np.asarray(gw['phase_l2_m2/X'])[6:] + gw_sxs_bbh_0305_pha_int = romspline.ReducedOrderSpline(times, gw_sxs_bbh_0305_pha) + + tmin=max(times_1[0],times[0]) + tmax=min(times_1[-1],times[-1]) + times=np.arange(tmin,tmax,dt) + amps=gw_sxs_bbh_0305_amp_int(times) + phs=gw_sxs_bbh_0305_pha_int(times) + gw_sxs_bbh_0305 = np.asarray([times,amps*np.cos(phs),amps*np.sin(phs)]).T + gw5_sxs_bbh_0305 = gw_sxs_bbh_0305 + + times = gw_sxs_bbh_0305[:,0] + tmax=rd_ut.FindTmaximum(gw_sxs_bbh_0305[round(len(gw_sxs_bbh_0305)/2):]) + times = times - tmax + + #times 6--> x axis of your data + times5 = gw5_sxs_bbh_0305[:,0] + tmax5=rd_ut.FindTmaximum(gw5_sxs_bbh_0305[round(len(gw_sxs_bbh_0305)/2):]) + times5 = times5 - tmax5 + #Select the data from 0 onwards + position = np.argmax( times >= (t_align)) + position5 = np.argmax(times5 >= (t_align)) + gw_sxs_bbh_0305rd=gw_sxs_bbh_0305[position+1:] + gw_sxs_bbh_0305rd5=gw5_sxs_bbh_0305[position5+1:] + timesrd=gw_sxs_bbh_0305[position:-1][:,0][:] + timesrd5=gw5_sxs_bbh_0305[position5:-1][:,0][:] + + elif nr_code=='LaZeV': + dt=0.1 + gw = {} + gw = h5py.File(simulation_path_1, 'r') + gw_sxs_bbh_0305_amp = np.asarray(gw['amp_l2_m2/Y'])[6:] + times_1 = np.asarray(gw['amp_l2_m2/X'])[6:] + gw_sxs_bbh_0305_amp_int = romspline.ReducedOrderSpline(times_1, gw_sxs_bbh_0305_amp) + gw_sxs_bbh_0305_pha = np.asarray(gw['phase_l2_m2/Y'])[6:] + times = np.asarray(gw['phase_l2_m2/X'])[6:] + gw_sxs_bbh_0305_pha_int = romspline.ReducedOrderSpline(times, gw_sxs_bbh_0305_pha) + + tmin=max(times_1[0],times[0]) + tmax=min(times_1[-1],times[-1]) + times=np.arange(tmin,tmax,dt) + amps=gw_sxs_bbh_0305_amp_int(times) + phs=gw_sxs_bbh_0305_pha_int(times) + gw_sxs_bbh_0305 = np.asarray([times,amps*np.cos(phs),amps*np.sin(phs)]).T + gw5_sxs_bbh_0305 = gw_sxs_bbh_0305 + + times = gw_sxs_bbh_0305[:,0] + tmax=rd_ut.FindTmaximum(gw_sxs_bbh_0305[round(len(gw_sxs_bbh_0305)/2):]) + times = times - tmax + + #times 6--> x axis of your data + times5 = gw5_sxs_bbh_0305[:,0] + tmax5=rd_ut.FindTmaximum(gw5_sxs_bbh_0305[round(len(gw_sxs_bbh_0305)/2):]) + times5 = times5 - tmax5 + + #Select the data from 0 onwards + position = np.argmax( times >= (t_align)) + position5 = np.argmax(times5 >= (t_align)) + gw_sxs_bbh_0305rd=gw_sxs_bbh_0305[position+1:] + gw_sxs_bbh_0305rd5=gw5_sxs_bbh_0305[position5+1:] + timesrd=gw_sxs_bbh_0305[position:-1][:,0][:] + timesrd5=gw5_sxs_bbh_0305[position5:-1][:,0][:] + + elif nr_code=='Mock-data': + times = np.arange(tshift,tend+10,0.1) + + nm_mock = parser.get('rd-mock-parameters','nm_mock') + nm_mock = np.int(nm_mock) + mf = parser.get('rd-mock-parameters','mf') + mf = np.float(mf) + af = np.float(parser.get('rd-mock-parameters','af')) + af = np.float(af) + + rdown=rd.Ringdown_Spectrum(mf,af,2,2,n=nm_mock,s=-2,time=times) + + w_mock=np.empty(nm_mock+1) + tau_mock=np.empty(nm_mock+1) + amp_mock=np.empty(nm_mock+1) + ph_mock=np.empty(nm_mock+1) + + for i in range(nm_mock+1): + wp_mock = parser.get('rd-mock-parameters','w'+str(i)) + w_mock[i] = np.float(wp_mock) + tp_mock=parser.get('rd-mock-parameters','tau'+str(i)) + tau_mock[i] = np.float(tp_mock) + amp_mockp = parser.get('rd-mock-parameters','amp'+str(i)) + amp_mock[i] = np.float(amp_mockp) + ph_mockp=parser.get('rd-mock-parameters','phase'+str(i)) + ph_mock[i] = np.float(ph_mockp) + + + pars = np.concatenate((w_mock,tau_mock,amp_mock,ph_mock)) + gw_data=rdown.rd_model_wtau(pars) + + return np.stack((times,gw_data)).T + +def nr_resize(data_1,data_2,tshift=0,tend=100): + times_1 = data_1[:,0].real + times_2 = data_2[:,0].real + data_1_re = data_1[:,1].real + data_1_im = data_1[:,1].imag + data_2_re = data_2[:,1].real + data_2_im = data_2[:,1].imag + + gwnew_re = interpolate.interp1d(times_1, data_1_re, kind = 'cubic') + gwnew_im = interpolate.interp1d(times_1, data_1_im, kind = 'cubic') + gwnew_re5 = interpolate.interp1d(times_2, data_2_re, kind = 'cubic') + gwnew_im5 = interpolate.interp1d(times_2, data_2_im, kind = 'cubic') + + if times_2[-1]>= times_1[-1]: + times_rd = times_1 + else: + times_rd = times_2 + + gwdatanew_re = gwnew_re(times_rd) + gwdatanew_im = gwnew_im(times_rd) + gwdatanew_re5 = gwnew_re5(times_rd) + gwdatanew_im5 = gwnew_im5(times_rd) + gwdatanew = gwdatanew_re + 1j*gwdatanew_im + gwdatanew5 = gwdatanew_re5 + 1j*gwdatanew_im5 + + position_in = np.argmax(times_rd >= tshift) + position_end = np.argmax(times_rd >= tend) + times_rd = times_rd[position_in:position_end] + gwdatanew = gwdatanew[position_in:position_end] + gwdatanew5 = gwdatanew5[position_in:position_end] + + return(np.stack((times_rd,gwdatanew)).T,np.stack((times_rd,gwdatanew5)).T) + + +def phase_align(data_1,data_2,t_align=0): + + #timesrd_final = data_1[:,0] + #phas = np.angle(data_1[:,1]) + #phas = np.unwrap(phas) + #phas5 = np.angle(data_2[:,1]) + #phas5 = np.unwrap(phas5) + #position = np.argmax(timesrd_final >= (t_align)) + #dphase = phas5[position]-phas[position] + + #gwdatanew = data_1[:,1]*np.exp(1j*dphase) + + + phas = np.angle(data_1[:,1]) + phas = np.unwrap(phas) + phas5 = np.angle(data_2[:,1]) + phas5 = np.unwrap(phas5) + position = np.argmax(data_1[:,0] >= (0)) + dphase = phas5[position]-phas[position] + gwdatanew = data_1[:,1]*np.exp(1j*dphase) + timesrd_final = data_1[:,0] + + return np.stack((timesrd_final,gwdatanew)).T + +def create_output_files(output_folder,pars,file_type): + sim_num, model, nmax, tshift, npoints = pars + + """ + Generate the output files you want to export the data to. + file_type must be one of this options: [corner_plot,corner_plot_extra,diagnosis,fit,post_samples,sampler_results,log_z] + """ + + if file_type=='corner_plot': + outfile = output_folder+'/Dynesty_'+str(sim_num)+'_'+model+'_nmax_'+str(nmax)+'_tshift_'+str(tshift)+'_'+str(npoints)+'corner_plot.png' + elif file_type=='corner_plot_extra': + outfile = output_folder+'/Dynesty_'+str(sim_num)+'_'+model+'_nmax_'+str(nmax)+'_tshift_'+str(tshift)+'_'+str(npoints)+'corner_plot_extra.png' + elif file_type=='diagnosis': + outfile = output_folder+'/Dynesty_diagnosis'+str(sim_num)+'_'+model+'_nmax_'+str(nmax)+'_tshift_'+str(tshift)+'_'+str(npoints)+'.png' + elif file_type=='fit': + outfile = output_folder+'/Fit_results_'+str(sim_num)+'tshift_'+str(tshift)+'_'+model+'_nmax_'+str(nmax)+'.png' + elif file_type=='post_samples': + outfile = output_folder+'/posterior_samples-'+str(sim_num)+'tshift_'+str(tshift)+'_'+model+'_nmax_'+str(nmax)+'.csv' + elif file_type=='sampler_results': + outfile = output_folder+'/results_'+str(sim_num)+'tshift_'+str(tshift)+'_'+model+'_nmax_'+str(nmax)+'.pkl' + elif file_type=='log_z': + outfile = output_folder+'/summary'+str(sim_num)+'_'+model+'_nmax_'+str(nmax)+'.csv' + elif file_type=='best_vals': + outfile = output_folder+'/best_values_'+str(sim_num)+'_'+model+'_nmax_'+str(nmax)+'.csv' + else: + print ('Something went wrong') + return + + return outfile + +def read_config_file(parser): + # Setup path and output folders + rootpath=parser.get('nr-paths','rootpath') + simulation_path_1 = parser.get('nr-paths','simulation_path_1') + + if parser.get('nr-paths','simulation_path_2'): + simulation_path_2 = parser.get('nr-paths','simulation_path_2') + else: + simulation_path_2 = simulation_path_1 + + metadata_file = parser.get('nr-paths','metadata_json') + simulation_number = parser.get('nr-paths','simulation_number') + simulation_number = np.int(simulation_number) + + output_folder = parser.get('output-folder','output-folder') + if parser.has_option('setup','export'): + export=eval(parser.get('setup','export')) + else: + export=True + + # Setup sampler and output options + overwrite = eval(parser.get('setup','overwrite')) + downfactor = np.int(parser.get('setup','plot_down_factor')) + sampler = parser.get('setup','sampler') + nr_code = parser.get('setup','nr_code') + if parser.has_option('setup','nb_cores'): + nbcores = np.int(parser.get('setup','nb_cores')) + else: + nbcores = 1 + + # time shift , end and align options + tshift=parser.get('time-setup','tshift') + tshift = np.float(tshift) + + tend=parser.get('time-setup','tend') + tend = np.float(tend) + + t_align=parser.get('time-setup','t_align') + t_align = np.float(t_align) + + # n-tones & nlive points + nmax=parser.get('n-tones','nmax') + nmax = np.int(nmax) + + npoints=parser.get('n-live-points','npoints') + npoints = np.int(npoints) + + # setup the RD model + model=parser.get('rd-model','model') + error_str = eval(parser.get('rd-model','error_str')) + fitnoise=eval(parser.get('rd-model','fit_noise')) + if fitnoise: + l_int=1 + index_mass=-3 + index_spin=-2 + # prior_dim = len(priors_min) + else: + index_mass=-2 + index_spin=-1 + l_int=0 + + if error_str: + error_val=np.float(parser.get('rd-model','error_val')) + if error_val==0: + error_type='' + else: + error_type=error_val + else: + error_type='False' + error_val =0 + + if nr_code == 'SXS': + metadata = {} + with open(metadata_file) as file: + metadata = json.load(file) + af = metadata['remnant_dimensionless_spin'][-1] + mf = metadata['remnant_mass'] + else: + mf = parser.get('rd-mock-parameters','mf') + mf = np.float(mf) + af = np.float(parser.get('rd-mock-parameters','af')) + af = np.float(af) + + if model == 'w-q': + tau_var_str='q' + else: + tau_var_str='tau' + + if nr_code == 'Mock-data': + nm_mock = int(parser.get('rd-mock-parameters','nm_mock')) + else: + nm_mock = None + + res = simulation_path_1,simulation_path_2, metadata_file , simulation_number, output_folder, export, overwrite, sampler,nr_code, nbcores,tshift,tend,t_align, nmax , npoints, model, error_str, fitnoise, l_int, index_mass,index_spin, error_type, error_val, af, mf,tau_var_str,nm_mock + return res \ No newline at end of file diff --git a/code_new/RD_Dynesty_Fits/dist/RD_Dynesty_Fits-0.1.0-py3.7.egg b/code_new/RD_Dynesty_Fits/dist/RD_Dynesty_Fits-0.1.0-py3.7.egg new file mode 100644 index 0000000000000000000000000000000000000000..b39d3a4a199f517e540e161c7cdf241830728e62 Binary files /dev/null and b/code_new/RD_Dynesty_Fits/dist/RD_Dynesty_Fits-0.1.0-py3.7.egg differ diff --git a/code_new/RD_Dynesty_Fits/pyproject.toml b/code_new/RD_Dynesty_Fits/pyproject.toml new file mode 100644 index 0000000000000000000000000000000000000000..3510d21927d37b6c7be21a9d87123c4885a7a8c7 --- /dev/null +++ b/code_new/RD_Dynesty_Fits/pyproject.toml @@ -0,0 +1,16 @@ +[build-system] +requires = [ + "setuptools>=42", + "wheel", + "corner", + "dynesty", + "json", + "h5py", + "qnm", + "pickle", + "pandas", + "csv", + "romspline", + "pytest", +] +build-backend = "setuptools.build_meta" diff --git a/code_new/RD_Dynesty_Fits/setup.cfg b/code_new/RD_Dynesty_Fits/setup.cfg new file mode 100644 index 0000000000000000000000000000000000000000..fd7d91305b31e029ca76c33f5287300018353e98 --- /dev/null +++ b/code_new/RD_Dynesty_Fits/setup.cfg @@ -0,0 +1,26 @@ +[metadata] +# replace with your username: +name = frcojimenez +version = 0.1 +author = Xisco Jimenez Forteza +author_email = francisco.jimenez.forteza@mpg.aei.de +description = A package that fits RD waveforms with the dynesty sampler +long_description = file: README.md +long_description_content_type = text/markdown +url = http://pypi.python.org/pypi/RD_Dynesty_Fits/ +project_urls = + Bug Tracker = https://github.com/frcojimenez/RD_Dynest_Fits/issues +classifiers = + Programming Language :: Python :: 3 + License :: OSI Approved :: MIT License + Operating System :: OS Independent + +[options] +package_dir = + = src +packages = find: +python_requires = >=3.6 + +[options.packages.find] +where = src +#There are a variety of metadata and option \ No newline at end of file diff --git a/code_new/RD_Dynesty_Fits/setup.py b/code_new/RD_Dynesty_Fits/setup.py new file mode 100644 index 0000000000000000000000000000000000000000..deb9e2b5a3f7b3fd493ec077b8e8bd62323a70c1 --- /dev/null +++ b/code_new/RD_Dynesty_Fits/setup.py @@ -0,0 +1,25 @@ +from setuptools import setup + +setup( + name='RD_Dynesty_Fits', + version='0.1.0', + author='Xisco Jimenez Forteza', + author_email='francisco.jimenez.forteza@mpg.aei.de', + packages=['RD_Dynesty_Fits', 'RD_Dynesty_Fits.test'], + package_dir={'':'/work/francisco.jimenez/sio/git/rdstackingproject/code_new/RD_Dynesty_Fits'}, + scripts=['src/RD_Dynesty_Fits.py','src/rdown_pe.py','src/rdown_utilities.py','src/rdown.py','src/read_data.py'], + url='http://pypi.python.org/pypi/RD_Dynesty_Fits/', + license='LICENSE.txt', + description='A package that fits RD waveforms with the dynesty sampler', + long_description=open('README.md').read(), + install_requires=["setuptools>=42", + "wheel", + "corner", + "dynesty", + "h5py", + "qnm", + "pandas", + "romspline", + "pytest", + ], +) diff --git a/code_new/RD_Dynesty_Fits/src/.ipynb_checkpoints/rdown-checkpoint.py b/code_new/RD_Dynesty_Fits/src/.ipynb_checkpoints/rdown-checkpoint.py new file mode 100644 index 0000000000000000000000000000000000000000..1357ccbf98a454670c79fb49574d7fe1447e243a --- /dev/null +++ b/code_new/RD_Dynesty_Fits/src/.ipynb_checkpoints/rdown-checkpoint.py @@ -0,0 +1,208 @@ +# Copyright (C) 2021 Xisco Jimenez Forteza +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + +# +# ============================================================================= +# +# Preamble +# +# ============================================================================= +# +# Module to generate RD waveforms. + +import numpy as np +import qnm +import os + +f_fpars= [[2.95845, -2.58697, 0.0533469], [2.12539, -1.78054, 0.0865503], [1.74755, -1.44776, 0.123666], [1.78287, -1.53203, 0.129475], [2.04028, -1.83224, 0.112497]] +q_fpars=[[0.584077, 1.52053, -0.480658], [0.00561441, 0.630715, -0.432664], [-0.197965, 0.515956, -0.369706], [-0.275097, 0.455691, -0.331543], [-0.287596, 0.398514, -0.309799]] + + +c=2.99792458*10**8;G=6.67259*10**(-11);MS=1.9885*10**30; +class Ringdown_Spectrum: + """RDown model generator""" + def __init__(self,mf,af,l,m,n=4,s=-2,time=[],fixed=False,qnm_model='berti'): + self.mf = mf + self.af = af + self.l = l + self.m = m + self.n = n + self.time = time + self.grav_220 = [qnm.modes_cache(s=s,l=self.l,m=self.m,n=i) for i in range (0,self.n+1)] + self.dim = self.n+1 + self.fixed = fixed + self.qnm_model = qnm_model + dict_omega = {'berti': self.QNM_Berti , 'qnm': self.QNM_spectrum} + dic = {'w-tau':self.rd_model_wtau , 'w-q': self.rd_model_wq, 'w-tau-fixed':self.rd_model_wtau_fixed,'w-tau-fixed-m-af': self.rd_model_wtau_m_af} + + if len(self.time)==0: + self.time = np.arange(0,100,0.1) + + if self.fixed: + omegas_new=np.asarray([self.grav_220[i](a=self.af)[0] for i in range (0,self.dim)]) + self.w = (np.real(omegas_new))/self.mf + self.tau=-1/(np.imag(omegas_new))*self.mf + + + def QNM_spectrum(self): + """ It computes the RD frequencies and damping times in NR units. + """ + omegas_new=np.asarray([self.grav_220[i](a=self.af)[0] for i in range (0,self.n+1)]) + w_m_a = (np.real(omegas_new))/self.mf + tau_m_a=-1/(np.imag(omegas_new))*self.mf + + return (w_m_a, tau_m_a) + + def QNM_Berti(self,rdowndata): + """ It computes the RD frequencies and damping times in NR units. + """ + position=np.argmax(rdowndata[0,0] >= (self.af)) + #w_m_a=f1+f2*(1-af)**f3 + w_m_a=[None]*(self.n+1) + tau_ma_a=[None]*(self.n+1) + + for i in range(self.n+1): + qnm=rdowndata[i,1:3,position] + w_m_a[i] = qnm[0]/self.mf + tau_ma_a[i] = -1/(qnm[1])*self.mf + + return w_m_a, tau_ma_a + + + def w_fpars_Berti(self,n): + return f_fpars[n] + + def tau_qpars_Berti(self,n): + return q_fpars[n] + + def mass_from_wtau(self,n,w,tau): + f1,f2,f3 = w_fpars_Berti(n) + q1,q2,q3 = tau_qpars_Berti(n) + res=(f1 + f2*(2**(-1/q3)*((-2*q1 + w*tau)/q2)**(1/q3))**f3)/w + return res + + def spin_from_wtau(self,n,w,tau): + f1,f2,f3 = w_fpars_Berti(n) + q1,q2,q3 = tau_qpars_Berti(n) + res=1 - 2**(-1/q3)*((-2*q1 + w*tau)/q2)**(1/q3) + return res + + def mass_from_wtau_loop(self,w,tau,l,m): + res=[None]*dim + for n in range (0,dim): + f1,f2,f3 = w_fpars_Berti(n) + q1,q2,q3 = tau_qpars_Berti(n) + res[n]=(f1 + f2*(2**(-1/q3)*((-2*q1 + w[n]*tau[n])/q2)**(1/q3))**f3)/w[n] + return res + + def spin_from_wtau_loop(self,w,tau,l,m): + res=[None]*dim + for n in range (0,dim): + f1,f2,f3 = w_fpars_Berti(n) + q1,q2,q3 = tau_qpars_Berti(n) + res[n]= 1 - 2**(-1/q3)*((-2*q1 + w[n]*tau[n])/q2)**(1/q3) + return res + + + def rd_model_wtau(self,theta): + """RD model parametrized with the damping time tau. + """ + assert int(len(theta)/4) == self.dim, 'Please recheck your n and parameters' + + wvars = theta[ : (self.dim)] + tvars = theta[(self.dim) : 2*(self.dim)] + xvars = theta[2*(self.dim) : 3*(self.dim)] + yvars = theta[3*(self.dim) : ] + + ansatz = 0 + for i in range (0,self.dim): + ansatz += (xvars[i]*np.exp(1j*yvars[i]))*np.exp(-self.time/tvars[i]) * (np.cos(wvars[i]*self.time)-1j*np.sin(wvars[i]*self.time)) + # -1j to agree with SXS convention + return ansatz + + def rd_model_wtau_m_af(theta): + """RD model parametrized with the damping time tau and with the QNM spectrum fixd to GR. The QNM spectrum is given from the mass and spin. + """ + xvars = theta[ : (dim)] + yvars = theta[(dim) : 2*(dim)] + mass_vars = theta[index_mass] + spin_vars = theta[index_spin] + + w_m_a , tau_m_a = dict_omega[self.qnm_model](mass_vars,spin_vars,2,2) + + ansatz = 0 + for i in range (0,dim): + ansatz += (xvars[i]*np.exp(1j*yvars[i]))*np.exp(-timesrd_final_tsh/tau_m_a[i]) * (np.cos(w_m_a[i]*timesrd_final_tsh)-1j*np.sin(w_m_a[i]*timesrd_final_tsh)) + # -1j to agree with SXS convention + return ansatz + + def rd_model_wtau_fixed(theta): + """RD model parametrized with the damping time tau and with the QNM spectrum fixd to GR. + """ + xvars = theta[ : (dim)] + yvars = theta[(dim) : 2*(dim)] + + ansatz = 0 + for i in range (0,dim): + ansatz += (xvars[i]*np.exp(1j*yvars[i]))*np.exp(-timesrd_final_tsh/tau[i]) * (np.cos(w[i]*timesrd_final_tsh)-1j*np.sin(w[i]*timesrd_final_tsh)) + # -1j to agree with SXS convention + return ansatz + + def rd_model_wq(self,theta): + """RD model parametrized with the quality factor q. + """ + assert int(len(theta)/4) == self.dim, 'Please recheck your n and parameters' + + wvars = theta[ : (self.dim)] + qvars = theta[(self.dim) : 2*(self.dim)] + xvars = theta[2*(self.dim) : 3*(self.dim)] + yvars = theta[3*(self.dim) : ] + + ansatz = 0 + for i in range (0,self.dim): + ansatz += (xvars[i]*np.exp(1j*yvars[i]))*np.exp(-self.time*np.pi*wvars[i]/qvars[i])*(np.cos(wvars[i]*self.time)-1j*np.sin(wvars[i]*self.time)) + # -1j to agree with SXS convention + return ansatz + + def rd_model_wq_fixed(self,theta): + """RD model parametrized with the damping time tau and with the QNM spectrum fixd to GR. + """ + xvars = theta[ : (self.dim)] + yvars = theta[(self.dim) : 2*(self.dim)] + + ansatz = 0 + for i in range (0,self.dim): + ansatz += (xvars[i]*np.exp(1j*yvars[i]))*np.exp(-self.time/self.tau[i]) * (np.cos(self.w[i]*self.time)-1j*np.sin(self.w[i]*self.time)) + # -1j to agree with SXS convention + return ansatz + + + def rd_model_wq_m_a(self,theta): + """RD model parametrized with the damping time tau and with the QNM spectrum fixd to GR. The QNM spectrum is given from the mass and spin. + """ + xvars = theta[ : (self.dim)] + yvars = theta[(self.dim) : 2*(self.dim)] + mass_vars = theta[-2] + spin_vars = theta[-1] + + w_m_a , tau_m_a = QNM_spectrum() + + ansatz = 0 + for i in range (0,dim): + ansatz += (xvars[i]*np.exp(1j*yvars[i]))*np.exp(-timesrd_final_tsh/tau_m_a[i]) * (np.cos(w_m_a[i]*timesrd_final_tsh)-1j*np.sin(w_m_a[i]*timesrd_final_tsh)) + # -1j to agree with SXS convention + return ansatz \ No newline at end of file diff --git a/code_new/RD_Dynesty_Fits/src/.ipynb_checkpoints/rdown_utilities-checkpoint.py b/code_new/RD_Dynesty_Fits/src/.ipynb_checkpoints/rdown_utilities-checkpoint.py new file mode 100644 index 0000000000000000000000000000000000000000..c4a5b95c1c26beb418d2457fbd2a2b09212778c3 --- /dev/null +++ b/code_new/RD_Dynesty_Fits/src/.ipynb_checkpoints/rdown_utilities-checkpoint.py @@ -0,0 +1,318 @@ +# Copyright (C) 2021 Xisco Jimenez Forteza +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + +# +# ============================================================================= +# +# Preamble +# +# ============================================================================= +# +# Module to run PE on RD data +import numpy as np +from dynesty.utils import resample_equal +from dynesty import utils as dyfunc +import os +import csv +import pandas as pd +import pickle + +def posterior_samples(sampler): + """ + Returns posterior samples from nested samples and weights + given by dynsety sampler + """ + + dynesty_samples = sampler.results['samples'] + wt = np.exp(sampler.results['logwt'] - + sampler.results['logz'][-1]) + # Make sure that sum of weights equal to 1 + weights = wt/np.sum(wt) + posterior_dynesty = dyfunc.resample_equal(dynesty_samples, weights) + return posterior_dynesty + +def FFT_FreqBins(times): + Len = len(times) + DeltaT = times[-1]- times[0] + dt = DeltaT/(Len-1) + dnu = 1/(Len*dt) + maxfreq = 1/(2*dt) + add = dnu/4 + + p = np.arange(0.0,maxfreq+add,dnu) + m = np.arange(p[-1]-(2*maxfreq)+dnu,-dnu/2+add,dnu) + res=np.concatenate((p,m)) + + return res + +def hFromPsi4FFI(tpsi4,f0): + + timecheck1=tpsi4[-2,0]-tpsi4[-1,0] + timecheck2=tpsi4[1,0]-tpsi4[0,0] + + if np.abs(timecheck1-timecheck2)>=0.0001: + print("The data might not be equally sampled!!") + + times,data= tpsi4[:,0],tpsi4[:,1] + + freqs = FT_FreqBins(xaxis.real).real + position = np.argmax(freqs >= f0) + freqs[:position]=f0*np.ones(len(freqs[:position])) + freqs=2*np.pi*freqs + + fdata=fft(data) + len(myTable)*ifft(- fdata/floor**2); + np.stack((times,data)).T + + +def twopoint_autocovariance(t,n): + """ It computes the two-point autocovariance function. + """ + dt=t[1]-t[0] + res = np.zeros(len(n)) + taus = np.zeros(len(n)) + for tau in range(0,int(len(n)/2)): + ntau=np.roll(n, tau) + taus[tau] = t[tau] + res[tau]=np.sum(n*ntau).real + return (taus[:int(len(n)/2)],res[:int(len(n)/2)]) + +def save_object(obj, filename): + with open(filename, 'wb') as output: # Overwrites any existing file. + pickle.dump(obj, output, pickle.HIGHEST_PROTOCOL) + + +def EasyMatchT(t,h1,h2,tmin,tmax): + """ It computes the time-domain match for (h1|h2) complex waveforms. + """ + pos = np.argmax(t >= (tmin)); + + h1red=h1[pos:]; + h2red=h2[pos:]; + + norm1=np.sum(np.abs(h1red)**2) + norm2=np.sum(np.abs(h2red)**2) + + myTable=h1red*np.conjugate(h2red) + res=((np.sum(myTable)/np.sqrt(norm1*norm2))).real + + return res + +def EasySNRT(t,h1,h2,tmin,tmax): + """ It computes the time-domain snr for (h1|h2) complex waveforms. + """ + pos = np.argmax(t >= (tmin)); + + h1red=h1[pos:]; + h2red=h2[pos:]; + + myTable=h1red*np.conjugate(h2red) + res=2*np.sqrt((np.sum(myTable)).real) + + return res + +def FindTmaximum(y): + """ It determines the maximum absolute value of the complex waveform. + """ + absval = np.sqrt(y[:,1]*y[:,1]+y[:,2]*y[:,2]) + vmax=np.max(absval) + index = np.argmax(absval == vmax) + timemax=y[index,0] + + return timemax + +def export_logz_files(output_file,pars): + sim_num, nmax, tshift, evidence, evidence_error = pars + + """ + Generate the logz.csv files you want to export the data to. + file_type must be one of this options: [corner_plot,corner_plot_extra,diagnosis,fit,post_samples,sampler_results,log_z] + """ + + summary_titles=['n','id','t_shift','dlogz','dlogz_err'] + if os.path.exists(output_file): + outvalues = np.array([[nmax, sim_num, tshift, evidence,evidence_error]]) + else: + outvalues = np.array([summary_titles,[nmax, sim_num, tshift, evidence,evidence_error]]) + + with open(output_file, 'a') as file: + writer = csv.writer(file) + if (outvalues.shape)[0]>1 : + writer.writerows(outvalues) + else: + writer.writerow(outvalues[0]) + + return + +def export_bestvals_files(best_data_file,postsamps,pars): + + tshift, lenpriors, labels = pars + + sigma_vars_m = np.empty(lenpriors) + sigma_vars_p = np.empty(lenpriors) + sigma_vars = np.empty(lenpriors) + sigma_vars_ml = np.empty(lenpriors) + for i in range(lenpriors): + amps_aux = postsamps[:,i] + sigma_vars_m[i] = np.quantile(amps_aux, 0.05) + sigma_vars[i] = np.quantile(amps_aux, 0.5) + sigma_vars_ml[i] = postsamps[-1,i] + sigma_vars_p[i] = np.quantile(amps_aux, 0.95) + + sigma_vars_all = [sigma_vars,sigma_vars_ml,sigma_vars_m,sigma_vars_p] + sigma_vars_all=np.stack([sigma_vars,sigma_vars_ml,sigma_vars_m,sigma_vars_p], axis=0) + + key =['max val','max val ml','lower bound','higher bound'] + dfslist = [pd.DataFrame(np.concatenate(([tshift],sigma_vars_all[i])).reshape((-1,lenpriors+1)), columns=np.concatenate((['tshift'],labels)), index = [key[i]]) for i in range(4)] + df2 = pd.concat(dfslist) + if os.path.exists(best_data_file): + df2.to_csv(best_data_file, mode='a', header=False,index = True) + else: + df2.to_csv(best_data_file, index = True) + + + +def define_labels(dim,model,fitnoise): + wstr = r'$\omega_' + + if model == 'w-tau': + taustr = r'$\tau_' + elif model == 'w-q': + taustr = r'$q_' + elif model == 'w-tau-fixed': + taustr = r'$dumb_var}' + elif model == 'w-tau-fixed-m-af': + taustr = r'$\tau_' + + ampstr = r'$A_' + phasestr = r'$\phi_' + + w_lab = [None] * dim + tau_lab = [None] * dim + amp_lab = [None] * dim + pha_lab = [None] * dim + mass_lab = ['mass'] + spin_lab = ['spin'] + + for i in range(dim): + w_lab[i] = wstr+str(i)+'$' + tau_lab[i] = taustr+str(i)+'$' + amp_lab[i] = ampstr+str(i)+'$' + pha_lab[i] = phasestr+str(i)+'$' + + + labels = np.concatenate((w_lab,tau_lab,amp_lab,pha_lab)) + + if model=='w-tau-fixed': + labels = np.concatenate((amp_lab,pha_lab)) + + if model=='w-tau-fixed-m-af': + pha_lab[i] = phasestr+str(i)+'$' + + labels = np.concatenate((amp_lab,pha_lab,mass_lab,spin_lab)) + + if fitnoise: + noise_lab = ['noise'] + labels = np.concatenate((labels,noise_lab)) + + return labels + +def get_truths(model,pars,fitnoise): + w, tau, mf, af , npamps = pars + if model == 'w-q': + tau_val = np.pi*w*tau + truths = np.concatenate((w,tau_val,npamps)) + elif model == 'w-tau': + tau_val = tau + truths = np.concatenate((w,tau_val,npamps)) + elif model == 'w-tau-fixed': + truths = npamps + elif model == 'w-tau-fixed-m-af': + truths = np.concatenate((npamps,[mf],[af])) + + if fitnoise: + truths = np.concatenate((truths,[1])) + + return truths + +def get_best_amps(pars,parser=None,nr_code=None): + nmax,model,samps_tr,half_points = pars + + + if model=='w-tau-fixed': + rg = (nmax+1) + elif model=='w-tau-fixed': + rg = (nmax+1)+2 + else: + rg = (nmax+1)*2 + + + if model=='w-tau-fixed-a-mf': + npamps = np.empty((nmax+1)) + for i in range(0,(nmax+1)): + amps_aux = samps_tr[i+rg][half_points:-1] + npamps[i] = np.quantile(amps_aux, 0.5) + else : + npamps = np.empty((nmax+1)*2) + for i in range(0,(nmax+1)*2): + amps_aux = samps_tr[i][half_points:-1] + npamps[i] = np.quantile(amps_aux, 0.5) + + if nr_code == 'Mock-data': + nm_mock = parser.get('rd-mock-parameters','nm_mock') + nm_mock = np.int(nm_mock) + amp_mock=np.empty(nm_mock+1) + ph_mock=np.empty(nm_mock+1) + for i in range(nm_mock+1): + amp_mockp = parser.get('rd-mock-parameters','amp'+str(i)) + amp_mock[i] = np.float(amp_mockp) + ph_mockp=parser.get('rd-mock-parameters','phase'+str(i)) + ph_mock[i] = np.float(ph_mockp) + + npamps = np.concatenate((amp_mock,ph_mock)) + return npamps + +def convert_m_af_2_w_tau_post(res,fitnoise=False): + + samples_2=res.samples + samps=f2.results.samples + + if fitnoise: + fmass_spin=(samps.T)[-3:-1].T + else: + fmass_spin=(samps.T)[-2:].T + #fmass_spin=new_samples[-2:] + fmass_spin_dist=[None]*len(fmass_spin) + weight=np.exp(res.logwt - res.logz[-1]) + for i in range(len(fmass_spin)): + fmass_spin_dist[i]=np.concatenate(dict_omega[qnm_model](fmass_spin[i,0],fmass_spin[i,1],2,2)) + + fmass_spin_dist_v2=np.asarray(fmass_spin_dist) + new_samples = dyfunc.resample_equal(fmass_spin_dist_v2, weight) + + return new_samples + +def save_object(obj, filename): + with open(filename, 'wb') as output: # Overwrites any existing file. + pickle.dump(obj, output, pickle.HIGHEST_PROTOCOL) + +def rm_files(files): + """ rm all old files """ + for i in files: + if os.path.exists(i): + os.remove(i) + \ No newline at end of file diff --git a/code_new/RD_Dynesty_Fits/src/.ipynb_checkpoints/read_data-checkpoint.py b/code_new/RD_Dynesty_Fits/src/.ipynb_checkpoints/read_data-checkpoint.py new file mode 100644 index 0000000000000000000000000000000000000000..87185de6364a1b89cb9223329e31dc5bb3e58391 --- /dev/null +++ b/code_new/RD_Dynesty_Fits/src/.ipynb_checkpoints/read_data-checkpoint.py @@ -0,0 +1,344 @@ +# Copyright (C) 2021 Xisco Jimenez Forteza +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + +# +# ============================================================================= +# +# Preamble +# +# ============================================================================= +# +# Module to run PE on RD data +import numpy as np +import rdown_utilities as rd_ut +import romspline +import rdown as rd +import h5py +import json +from scipy import interpolate +from scipy.interpolate import interp1d + + +def read_data(nr_code,sim_path,mf=1,af=0,parser=None,RD=True,tshift=0,tend = 100,metadata_file=None): + if nr_code=='SXS': + gw = {} + gw = h5py.File(sim_path, 'r') + gw_data = gw["Extrapolated_N3.dir"]["Y_l2_m2.dat"] + times = gw_data[:,0] + + metadata = {} + with open(metadata_file) as file: + metadata = json.load(file) + + af = metadata['remnant_dimensionless_spin'][-1] + mf = metadata['remnant_mass'] + + tmax=rd_ut.FindTmaximum(gw_data[round(len(gw_data)/2):]) + times = times - tmax + + if RD: + position = np.argmax(times >= 0) + gw_data = gw_data[:,1][position:]+1j*gw_data[:,2][position:] + times = times[times >= 0] + + elif nr_code=='Maya': + dt=0.1 + gw = {} + gw = h5py.File(sim_path, 'r') + gw_sxs_bbh_0305_amp = np.asarray(gw['amp_l2_m2/Y'])[6:] + times_1 = np.asarray(gw['amp_l2_m2/X'])[6:] + gw_sxs_bbh_0305_amp_int = romspline.ReducedOrderSpline(times_1, gw_sxs_bbh_0305_amp) + gw_sxs_bbh_0305_pha = np.asarray(gw['phase_l2_m2/Y'])[6:] + times = np.asarray(gw['phase_l2_m2/X'])[6:] + gw_sxs_bbh_0305_pha_int = romspline.ReducedOrderSpline(times, gw_sxs_bbh_0305_pha) + + tmin=max(times_1[0],times[0]) + tmax=min(times_1[-1],times[-1]) + times=np.arange(tmin,tmax,dt) + amps=gw_sxs_bbh_0305_amp_int(times) + phs=gw_sxs_bbh_0305_pha_int(times) + gw_sxs_bbh_0305 = np.asarray([times,amps*np.cos(phs),amps*np.sin(phs)]).T + gw5_sxs_bbh_0305 = gw_sxs_bbh_0305 + + times = gw_sxs_bbh_0305[:,0] + tmax=rd_ut.FindTmaximum(gw_sxs_bbh_0305[round(len(gw_sxs_bbh_0305)/2):]) + times = times - tmax + + #times 6--> x axis of your data + times5 = gw5_sxs_bbh_0305[:,0] + tmax5=rd_ut.FindTmaximum(gw5_sxs_bbh_0305[round(len(gw_sxs_bbh_0305)/2):]) + times5 = times5 - tmax5 + #Select the data from 0 onwards + position = np.argmax( times >= (t_align)) + position5 = np.argmax(times5 >= (t_align)) + gw_sxs_bbh_0305rd=gw_sxs_bbh_0305[position+1:] + gw_sxs_bbh_0305rd5=gw5_sxs_bbh_0305[position5+1:] + timesrd=gw_sxs_bbh_0305[position:-1][:,0][:] + timesrd5=gw5_sxs_bbh_0305[position5:-1][:,0][:] + + elif nr_code=='LaZeV': + dt=0.1 + gw = {} + gw = h5py.File(simulation_path_1, 'r') + gw_sxs_bbh_0305_amp = np.asarray(gw['amp_l2_m2/Y'])[6:] + times_1 = np.asarray(gw['amp_l2_m2/X'])[6:] + gw_sxs_bbh_0305_amp_int = romspline.ReducedOrderSpline(times_1, gw_sxs_bbh_0305_amp) + gw_sxs_bbh_0305_pha = np.asarray(gw['phase_l2_m2/Y'])[6:] + times = np.asarray(gw['phase_l2_m2/X'])[6:] + gw_sxs_bbh_0305_pha_int = romspline.ReducedOrderSpline(times, gw_sxs_bbh_0305_pha) + + tmin=max(times_1[0],times[0]) + tmax=min(times_1[-1],times[-1]) + times=np.arange(tmin,tmax,dt) + amps=gw_sxs_bbh_0305_amp_int(times) + phs=gw_sxs_bbh_0305_pha_int(times) + gw_sxs_bbh_0305 = np.asarray([times,amps*np.cos(phs),amps*np.sin(phs)]).T + gw5_sxs_bbh_0305 = gw_sxs_bbh_0305 + + times = gw_sxs_bbh_0305[:,0] + tmax=rd_ut.FindTmaximum(gw_sxs_bbh_0305[round(len(gw_sxs_bbh_0305)/2):]) + times = times - tmax + + #times 6--> x axis of your data + times5 = gw5_sxs_bbh_0305[:,0] + tmax5=rd_ut.FindTmaximum(gw5_sxs_bbh_0305[round(len(gw_sxs_bbh_0305)/2):]) + times5 = times5 - tmax5 + + #Select the data from 0 onwards + position = np.argmax( times >= (t_align)) + position5 = np.argmax(times5 >= (t_align)) + gw_sxs_bbh_0305rd=gw_sxs_bbh_0305[position+1:] + gw_sxs_bbh_0305rd5=gw5_sxs_bbh_0305[position5+1:] + timesrd=gw_sxs_bbh_0305[position:-1][:,0][:] + timesrd5=gw5_sxs_bbh_0305[position5:-1][:,0][:] + + elif nr_code=='Mock-data': + times = np.arange(tshift,tend+10,0.1) + + nm_mock = parser.get('rd-mock-parameters','nm_mock') + nm_mock = np.int(nm_mock) + mf = parser.get('rd-mock-parameters','mf') + mf = np.float(mf) + af = np.float(parser.get('rd-mock-parameters','af')) + af = np.float(af) + + rdown=rd.Ringdown_Spectrum(mf,af,2,2,n=nm_mock,s=-2,time=times) + + w_mock=np.empty(nm_mock+1) + tau_mock=np.empty(nm_mock+1) + amp_mock=np.empty(nm_mock+1) + ph_mock=np.empty(nm_mock+1) + + for i in range(nm_mock+1): + wp_mock = parser.get('rd-mock-parameters','w'+str(i)) + w_mock[i] = np.float(wp_mock) + tp_mock=parser.get('rd-mock-parameters','tau'+str(i)) + tau_mock[i] = np.float(tp_mock) + amp_mockp = parser.get('rd-mock-parameters','amp'+str(i)) + amp_mock[i] = np.float(amp_mockp) + ph_mockp=parser.get('rd-mock-parameters','phase'+str(i)) + ph_mock[i] = np.float(ph_mockp) + + + pars = np.concatenate((w_mock,tau_mock,amp_mock,ph_mock)) + gw_data=rdown.rd_model_wtau(pars) + + return np.stack((times,gw_data)).T + +def nr_resize(data_1,data_2,tshift=0,tend=100): + times_1 = data_1[:,0].real + times_2 = data_2[:,0].real + data_1_re = data_1[:,1].real + data_1_im = data_1[:,1].imag + data_2_re = data_2[:,1].real + data_2_im = data_2[:,1].imag + + gwnew_re = interpolate.interp1d(times_1, data_1_re, kind = 'cubic') + gwnew_im = interpolate.interp1d(times_1, data_1_im, kind = 'cubic') + gwnew_re5 = interpolate.interp1d(times_2, data_2_re, kind = 'cubic') + gwnew_im5 = interpolate.interp1d(times_2, data_2_im, kind = 'cubic') + + if times_2[-1]>= times_1[-1]: + times_rd = times_1 + else: + times_rd = times_2 + + gwdatanew_re = gwnew_re(times_rd) + gwdatanew_im = gwnew_im(times_rd) + gwdatanew_re5 = gwnew_re5(times_rd) + gwdatanew_im5 = gwnew_im5(times_rd) + gwdatanew = gwdatanew_re + 1j*gwdatanew_im + gwdatanew5 = gwdatanew_re5 + 1j*gwdatanew_im5 + + position_in = np.argmax(times_rd >= tshift) + position_end = np.argmax(times_rd >= tend) + times_rd = times_rd[position_in:position_end] + gwdatanew = gwdatanew[position_in:position_end] + gwdatanew5 = gwdatanew5[position_in:position_end] + + return(np.stack((times_rd,gwdatanew)).T,np.stack((times_rd,gwdatanew5)).T) + + +def phase_align(data_1,data_2,t_align=0): + + #timesrd_final = data_1[:,0] + #phas = np.angle(data_1[:,1]) + #phas = np.unwrap(phas) + #phas5 = np.angle(data_2[:,1]) + #phas5 = np.unwrap(phas5) + #position = np.argmax(timesrd_final >= (t_align)) + #dphase = phas5[position]-phas[position] + + #gwdatanew = data_1[:,1]*np.exp(1j*dphase) + + + phas = np.angle(data_1[:,1]) + phas = np.unwrap(phas) + phas5 = np.angle(data_2[:,1]) + phas5 = np.unwrap(phas5) + position = np.argmax(data_1[:,0] >= (0)) + dphase = phas5[position]-phas[position] + gwdatanew = data_1[:,1]*np.exp(1j*dphase) + timesrd_final = data_1[:,0] + + return np.stack((timesrd_final,gwdatanew)).T + +def create_output_files(output_folder,pars,file_type): + sim_num, model, nmax, tshift, npoints = pars + + """ + Generate the output files you want to export the data to. + file_type must be one of this options: [corner_plot,corner_plot_extra,diagnosis,fit,post_samples,sampler_results,log_z] + """ + + if file_type=='corner_plot': + outfile = output_folder+'/Dynesty_'+str(sim_num)+'_'+model+'_nmax_'+str(nmax)+'_tshift_'+str(tshift)+'_'+str(npoints)+'corner_plot.png' + elif file_type=='corner_plot_extra': + outfile = output_folder+'/Dynesty_'+str(sim_num)+'_'+model+'_nmax_'+str(nmax)+'_tshift_'+str(tshift)+'_'+str(npoints)+'corner_plot_extra.png' + elif file_type=='diagnosis': + outfile = output_folder+'/Dynesty_diagnosis'+str(sim_num)+'_'+model+'_nmax_'+str(nmax)+'_tshift_'+str(tshift)+'_'+str(npoints)+'.png' + elif file_type=='fit': + outfile = output_folder+'/Fit_results_'+str(sim_num)+'tshift_'+str(tshift)+'_'+model+'_nmax_'+str(nmax)+'.png' + elif file_type=='post_samples': + outfile = output_folder+'/posterior_samples-'+str(sim_num)+'tshift_'+str(tshift)+'_'+model+'_nmax_'+str(nmax)+'.csv' + elif file_type=='sampler_results': + outfile = output_folder+'/results_'+str(sim_num)+'tshift_'+str(tshift)+'_'+model+'_nmax_'+str(nmax)+'.pkl' + elif file_type=='log_z': + outfile = output_folder+'/summary'+str(sim_num)+'_'+model+'_nmax_'+str(nmax)+'.csv' + elif file_type=='best_vals': + outfile = output_folder+'/best_values_'+str(sim_num)+'_'+model+'_nmax_'+str(nmax)+'.csv' + else: + print ('Something went wrong') + return + + return outfile + +def read_config_file(parser): + # Setup path and output folders + rootpath=parser.get('nr-paths','rootpath') + simulation_path_1 = parser.get('nr-paths','simulation_path_1') + + if parser.get('nr-paths','simulation_path_2'): + simulation_path_2 = parser.get('nr-paths','simulation_path_2') + else: + simulation_path_2 = simulation_path_1 + + metadata_file = parser.get('nr-paths','metadata_json') + simulation_number = parser.get('nr-paths','simulation_number') + simulation_number = np.int(simulation_number) + + output_folder = parser.get('output-folder','output-folder') + if parser.has_option('setup','export'): + export=eval(parser.get('setup','export')) + else: + export=True + + # Setup sampler and output options + overwrite = eval(parser.get('setup','overwrite')) + downfactor = np.int(parser.get('setup','plot_down_factor')) + sampler = parser.get('setup','sampler') + nr_code = parser.get('setup','nr_code') + if parser.has_option('setup','nb_cores'): + nbcores = np.int(parser.get('setup','nb_cores')) + else: + nbcores = 1 + + # time shift , end and align options + tshift=parser.get('time-setup','tshift') + tshift = np.float(tshift) + + tend=parser.get('time-setup','tend') + tend = np.float(tend) + + t_align=parser.get('time-setup','t_align') + t_align = np.float(t_align) + + # n-tones & nlive points + nmax=parser.get('n-tones','nmax') + nmax = np.int(nmax) + + npoints=parser.get('n-live-points','npoints') + npoints = np.int(npoints) + + # setup the RD model + model=parser.get('rd-model','model') + error_str = eval(parser.get('rd-model','error_str')) + fitnoise=eval(parser.get('rd-model','fit_noise')) + if fitnoise: + l_int=1 + index_mass=-3 + index_spin=-2 + # prior_dim = len(priors_min) + else: + index_mass=-2 + index_spin=-1 + l_int=0 + + if error_str: + error_val=np.float(parser.get('rd-model','error_val')) + if error_val==0: + error_type='' + else: + error_type=error_val + else: + error_type='False' + error_val =0 + + if nr_code == 'SXS': + metadata = {} + with open(metadata_file) as file: + metadata = json.load(file) + af = metadata['remnant_dimensionless_spin'][-1] + mf = metadata['remnant_mass'] + else: + mf = parser.get('rd-mock-parameters','mf') + mf = np.float(mf) + af = np.float(parser.get('rd-mock-parameters','af')) + af = np.float(af) + + if model == 'w-q': + tau_var_str='q' + else: + tau_var_str='tau' + + if nr_code == 'Mock-data': + nm_mock = int(parser.get('rd-mock-parameters','nm_mock')) + else: + nm_mock = None + + res = simulation_path_1,simulation_path_2, metadata_file , simulation_number, output_folder, export, overwrite, sampler,nr_code, nbcores,tshift,tend,t_align, nmax , npoints, model, error_str, fitnoise, l_int, index_mass,index_spin, error_type, error_val, af, mf,tau_var_str,nm_mock + return res \ No newline at end of file diff --git a/code_new/RD_Dynesty_Fits/src/RD_Dynesty_Fits.egg-info/PKG-INFO b/code_new/RD_Dynesty_Fits/src/RD_Dynesty_Fits.egg-info/PKG-INFO new file mode 100644 index 0000000000000000000000000000000000000000..83514320ecbdc9bfb32e098b22baab2e1bfcf565 --- /dev/null +++ b/code_new/RD_Dynesty_Fits/src/RD_Dynesty_Fits.egg-info/PKG-INFO @@ -0,0 +1,18 @@ +Metadata-Version: 2.1 +Name: RD-Dynesty-Fits +Version: 0.1.0 +Summary: A package that fits RD waveforms with the dynesty sampler +Home-page: http://pypi.python.org/pypi/RD-Dynesty-Fits/ +Author: Xisco Jimenez Forteza +Author-email: francisco.jimenez.forteza@mpg.aei.de +License: LICENSE.txt +Project-URL: Bug Tracker, https://github.com/frcojimenez/RD-Dynest-Fits/issues +Description: A package that fits RD waveforms with the dynesty sampler + + +Platform: UNKNOWN +Classifier: Programming Language :: Python :: 3 +Classifier: License :: OSI Approved :: MIT License +Classifier: Operating System :: OS Independent +Requires-Python: >=3.6 +Description-Content-Type: text/markdown diff --git a/code_new/RD_Dynesty_Fits/src/RD_Dynesty_Fits.egg-info/SOURCES.txt b/code_new/RD_Dynesty_Fits/src/RD_Dynesty_Fits.egg-info/SOURCES.txt new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/code_new/RD_Dynesty_Fits/src/RD_Dynesty_Fits.egg-info/dependency_links.txt b/code_new/RD_Dynesty_Fits/src/RD_Dynesty_Fits.egg-info/dependency_links.txt new file mode 100644 index 0000000000000000000000000000000000000000..8b137891791fe96927ad78e64b0aad7bded08bdc --- /dev/null +++ b/code_new/RD_Dynesty_Fits/src/RD_Dynesty_Fits.egg-info/dependency_links.txt @@ -0,0 +1 @@ + diff --git a/code_new/RD_Dynesty_Fits/src/RD_Dynesty_Fits.egg-info/requires.txt b/code_new/RD_Dynesty_Fits/src/RD_Dynesty_Fits.egg-info/requires.txt new file mode 100644 index 0000000000000000000000000000000000000000..c8a98c44436fc8e96121781ec38c78021b032938 --- /dev/null +++ b/code_new/RD_Dynesty_Fits/src/RD_Dynesty_Fits.egg-info/requires.txt @@ -0,0 +1,9 @@ +setuptools>=42 +wheel +corner +dynesty +h5py +qnm +pandas +romspline +pytest diff --git a/code_new/RD_Dynesty_Fits/src/RD_Dynesty_Fits.egg-info/top_level.txt b/code_new/RD_Dynesty_Fits/src/RD_Dynesty_Fits.egg-info/top_level.txt new file mode 100644 index 0000000000000000000000000000000000000000..3dd4cf60b3a76529c5ee75522f01ab4b62418492 --- /dev/null +++ b/code_new/RD_Dynesty_Fits/src/RD_Dynesty_Fits.egg-info/top_level.txt @@ -0,0 +1 @@ +RD_Dynesty_Fits diff --git a/code_new/RD_Dynesty_Fits/src/RD_Dynesty_Fits.py b/code_new/RD_Dynesty_Fits/src/RD_Dynesty_Fits.py new file mode 100755 index 0000000000000000000000000000000000000000..a8d13aac0567fe30ada2a645e23ee07072da0079 --- /dev/null +++ b/code_new/RD_Dynesty_Fits/src/RD_Dynesty_Fits.py @@ -0,0 +1,390 @@ +#!/usr/bin/env python +# coding: utf-8 + +# In[38]: + + +"""Generate ringdown templates in the time and perform parameter estimation on them. +""" + + +# In[1]: + + +#Import relevant modules, import data and all that +import time +import numpy as np +import corner +import matplotlib.pyplot as plt +from matplotlib.ticker import MaxNLocator +from matplotlib import rc +from configparser import ConfigParser +plt.rcParams.update({'font.size': 16.5}) + +from multiprocessing import Pool +import random +import dynesty +from dynesty import plotting as dyplot +from dynesty.utils import resample_equal +from dynesty import utils as dyfunc +import os +import argparse +import scipy.optimize as optimization +from scipy.optimize import minimize +import rdown as rd +import rdown_pe as rd_pe +import rdown_utilities as rd_ut +import read_data as rdata + + +# In[2]: + + +## Loading and running data tested with NR data +## Loading and running data tested with Mock data + + +# In[3]: + + +# Cell that calls the arguments from your 'config.ini' file. +try: + parser = argparse.ArgumentParser(description="Simple argument parser") + parser.add_argument("-c", action="store", dest="config_file") + result = parser.parse_args() + config_file=result.config_file + parser = ConfigParser() + parser.read(config_file) + parser.sections() +except SystemExit: + parser = ConfigParser() + parser.read('./run_0_mock/config_n0_to_1_mock.ini') + parser.sections() + pass + + +# In[4]: + + +# Load variables from config file +(simulation_path_1,simulation_path_2, metadata_file , simulation_number, output_folder, + export, overwrite, sampler,nr_code, nbcores,tshift,tend,t_align, + nmax , npoints, model, error_str, fitnoise, l_int, index_mass,index_spin, +error_type, error_val, af, mf,tau_var_str,nm_mock)=rdata.read_config_file(parser) + + +# In[5]: + + +# Show configuration options +dim = nmax+1 +ndim = 4*dim +numbins = 32 #corner plot parameter - how many bins you want + +print('model:',model) +print('nmax:',nmax) +print('nm_mock:',nm_mock) +print('tshift:',tshift) +print('error:', error_str) +print('error value:',error_val) +print('export:',export) +print('nr code:',nr_code) +print('fit noise:',fitnoise) + + +# In[6]: + + +# Create output directories +if not os.path.exists(output_folder): + os.mkdir(output_folder) + print("Directory " , output_folder , " Created ") + +if nr_code == 'Mock-data': + nm_mock_str = 'rec_with'+parser.get('rd-mock-parameters','nm_mock')+'_' +else: + nm_mock_str='' + +if error_str: + output_folder_1=(output_folder+'/'+model+'-nmax'+str(nmax)+'_'+nm_mock_str+str(error_str)+'_'+str(error_type)+'_fitnoise_'+str(fitnoise)) +else: + output_folder_1=output_folder+'/'+model+'-nmax'+str(nmax)+'_'+nm_mock_str+str(error_str)+'_'+'fitnoise_'+str(fitnoise) + +if not os.path.exists(output_folder_1): + os.mkdir(output_folder_1) + print("Directory " , output_folder_1 , " Created ") + + +# In[7]: + + +# Define output files +pars = [simulation_number,model,nmax,tshift,npoints] +corner_plot = rdata.create_output_files(output_folder_1,pars,'corner_plot') +corner_plot_extra = rdata.create_output_files(output_folder_1,pars,'corner_plot_extra') +diagnosis_plot = rdata.create_output_files(output_folder_1,pars,'diagnosis') +fit_plot = rdata.create_output_files(output_folder_1,pars,'fit') +samples_file = rdata.create_output_files(output_folder_1,pars,'post_samples') +results_file = rdata.create_output_files(output_folder_1,pars,'sampler_results') +sumary_data = rdata.create_output_files(output_folder_1,pars,'log_z') +best_data = rdata.create_output_files(output_folder_1,pars,'best_vals') + +files = [corner_plot,corner_plot_extra,diagnosis_plot,fit_plot,samples_file,results_file,sumary_data,best_data] + + +# In[8]: + + +# Remove old files if overwrite = True +if overwrite: + rd_ut.rm_files(files) + + +# In[46]: + + +#Load NR data, align in time and resize. Plot real part and amplitude. Finally compute the mismatch and the snr estimate +data = rdata.read_data(nr_code,simulation_path_1,RD=True,tshift=tshift,tend = tend,metadata_file=metadata_file,parser=parser) +data_l = rdata.read_data(nr_code,simulation_path_2,RD=True,tshift=tshift,tend = tend,metadata_file=metadata_file,parser=parser) +data_r, data_lr = rdata.nr_resize(data,data_l,tshift=tshift,tend=tend) +times_rd = data_r[:,0] + +plt.figure(figsize = (12, 8)) +plt.plot(times_rd, data_r[:,1].real, "r", alpha=0.3, lw=3, label=r'$Lev6$: real') +plt.plot(times_rd, np.sqrt((data_r[:,1].real)**2+(data_r[:,1].imag)**2), "r", alpha=0.3, lw=3, label=r'$Lev5\,amp$') +plt.plot(times_rd, data_lr[:,1].real, "b", alpha=0.3, lw=3, label=r'$Lev5: real$') +plt.plot(times_rd, np.sqrt((data_lr[:,1].real)**2+(data_lr[:,1].imag)**2), "b", alpha=0.3, lw=3, label=r'$Lev5\,amp$') +if error_str and error_val==0: + error = np.sqrt(data_r[:,1]*data_r[:,1]-2*data_r[:,1]*data_lr[:,1]+data_lr[:,1]*data_lr[:,1]) + error_est=np.sqrt(error.imag**2+error.real**2) + plt.plot(times_rd, error_est, "g", alpha=0.3, lw=2, label='error') +plt.legend() + +mismatch=1-rd_ut.EasyMatchT(times_rd,data_r[:,1],data_lr[:,1],tshift,tend) +error=np.sqrt(2*mismatch) +print('error estimate:',error) +print('mismatch:', mismatch) +print('snr:', rd_ut.EasySNRT(times_rd,data_r[:,1],data_lr[:,1],tshift,tend)/error**2) + + +# In[47]: + + +# Phase alignement +if parser.has_option('rd-model','phase_alignment'): + phase_alignment=eval(parser.get('rd-model','phase_alignment')) +else: + phase_alignment=False + +if phase_alignment: + datar_al = rdata.phase_align(data_r,data_lr) + gwdatanew5 = data_lr[:,1] + gwdatanew = datar_al[:,1] + timesrd_final = datar_al[:,0] + mismatch=1-rd_ut.EasyMatchT(timesrd_final,gwdatanew,gwdatanew5,tshift,tend) + error=np.sqrt(2*mismatch) + print('error estimate:',error) + print('mismatch:', mismatch) + print('snr:', rd_ut.EasySNRT(timesrd_final,gwdatanew,gwdatanew5,tshift,tend)/error) + if error_str: + error = np.sqrt(gwdatanew*gwdatanew-2*gwdatanew*gwdatanew5+gwdatanew5*gwdatanew5) + error_est=np.sqrt(error.imag**2+error.real**2) + else : + error = 1 +else: + datar_al = data_r + timesrd_final = datar_al[:,0] + +#Test the new interpolated data +if error_str and error_val==0: + plt.figure(figsize = (12, 8)) + plt.plot(timesrd_final, datar_al[:,1].real, "r", alpha=0.3, lw=2, label='Original') + plt.plot(timesrd_final, data_lr[:,1].real, "b", alpha=0.3, lw=2, label='Aligned') + plt.plot(timesrd_final, error_est, "b", alpha=0.3, lw=2, label='error') + plt.legend() + + +# In[48]: + + +# Define your noise depending on the noise configuration. Load priors and setup the likelihood with rd_pe.Ringdown_PE. +if error_str and error_val==0: + error_final = error_est + norm_factor = 100*len(error_final)/2*np.log(2*np.pi) +elif error_str and error_val!=0: + datar_al[:,1]+=random.uniform(0, error_val) + datar_al[:,1]+=1j*random.uniform(0, error_val) + error_tsh = error_val + error_final=(error_tsh.real**2+error_tsh.imag**2) + norm_factor = 0 +else: + error_tsh=1 + error_final=(error_tsh.real**2+error_tsh.imag**2) + norm_factor = 0 + +priors = rd_pe.load_priors(model,parser,nmax,fitnoise=fitnoise) +rdown=rd.Ringdown_Spectrum(mf,af,2,2,n=nmax,s=-2,time=timesrd_final) +rdown_pe = rd_pe.Ringdown_PE(rdown,datar_al,dim,priors,errors2=error_final,norm_factor=norm_factor,model=model,l_int=l_int) + + +# In[49]: + + +# Get a first estimate by trying to fit the data. +nll = lambda *args: -rdown_pe.log_likelihood(*args) +if model == 'w-tau-fixed-m-af': + if fitnoise: + initial = np.concatenate((np.ones(2*dim),[0.8,0.9,1])) + soln = minimize(nll, initial,bounds=priors) + vars_ml=soln.x + else: + initial = np.concatenate((np.ones(2*dim),[0.8,0.9])) + soln = minimize(nll, initial,bounds=priors) + vars_ml=soln.x +elif model == 'w-tau-fixed': + if fitnoise: + initial = np.concatenate((np.ones(2*dim),[0.2])) + soln = minimize(nll, initial,bounds=priors) + vars_ml=soln.x + else: + initial = np.ones(2*dim) + soln = minimize(nll, initial,bounds=priors) + vars_ml=soln.x +else: + if fitnoise: + initial = np.concatenate((np.ones(ndim),[1])) + soln = minimize(nll, initial,bounds=priors) + vars_ml=soln.x + else: + initial = np.ones(ndim) + soln = minimize(nll, initial,bounds=priors) + vars_ml=soln.x +print("best fit pars from fit: ",vars_ml) + + +# In[50]: + + +mypool = Pool(nbcores) +mypool.size = nbcores + +start = time.process_time() +f2=dynesty.NestedSampler(rdown_pe.log_likelihood,rdown_pe.prior_transform, len(priors), nlive=npoints,sample=sampler,pool=mypool) +if parser.has_option('setup','dlogz'): + dlogz=np.float(parser.get('setup','dlogz')) + f2.run_nested(dlogz=dlogz,print_progress=False) +else: + f2.run_nested(print_progress=False) + +print(time.process_time() - start) + + +# In[52]: + + +res = f2.results +res.samples_u.shape +res.summary() +samps=f2.results.samples +postsamps = rd_ut.posterior_samples(f2) +samps_tr=np.transpose(samps) +half_points=int(round((len(samps_tr[0])/1.25))) +evidence = res.logz[-1] +evidence_error = res.logzerr[-1] +if export: + rd_ut.save_object(res, results_file) + + +# In[53]: + + +pars = nmax,model,samps_tr, half_points +npamps = rd_ut.get_best_amps(pars,parser=parser,nr_code=nr_code) + + +# In[54]: + + +if export: + pars = simulation_number, nmax, tshift, evidence, evidence_error + rd_ut.export_logz_files(sumary_data,pars) + + +# In[55]: + + +labels = rd_ut.define_labels(dim,model,fitnoise) +if export: + pars = tshift, len(priors), labels + rd_ut.export_bestvals_files(best_data,postsamps,pars) + + +# In[56]: + + +w, tau = rdown.QNM_spectrum() +pars = w, tau, mf, af, npamps +truths = rd_ut.get_truths(model,pars,fitnoise) + + +# In[57]: + + +fg=corner.corner(postsamps,quantiles=[0.05,0.5,0.95],show_titles=True,max_n_ticks = 4,bins=50,truths=truths,labels=labels,truth_color='red') +plt.show() +if export: + fg.savefig(corner_plot, format = 'png', bbox_inches = 'tight') + + +# In[58]: + + +from importlib import reload +reload(rd_ut) +if model == 'w-tau-fixed-m-af' and export == True: + truths=np.concatenate((w,tau)) + labels_mf = np.concatenate((w_lab,tau_lab)) + new_samples = rd_ut.convert_m_af_2_w_tau_post(res,fitnoise=False) + figure = corner.corner(new_samples,truths=truths,quantiles=[0.05,0.95],labels=labels_mf,smooth=True,color='b',truth_color='r',show_titles=True) + figure.savefig(corner_plot_extra, format = 'png', bbox_inches = 'tight') + + +# In[151]: + + +#lnz_truth = ndim * -np.log(2 * 10.) # analytic evidence solution +fig, axes = dyplot.runplot(res) +fig.tight_layout() +if export: + fig.savefig(diagnosis_plot, format = 'png', dpi = 384, bbox_inches = 'tight') + + +# In[166]: + + +if export: + dict = {'w-tau':rdown.rd_model_wtau , 'w-q': rdown.rd_model_wq, 'w-tau-fixed':rdown.rd_model_wtau_fixed,'w-tau-fixed-m-af': rdown.rd_model_wtau_m_af} + figband = plt.figure(figsize = (12, 9)) + plt.plot(datar_al[:,0].real,datar_al[:,1].real, "green", alpha=0.9, lw=3, label=r'$res_{240}$') + onesig_bounds = np.array([np.percentile(postsamps[:, i], [5, 95]) for i in range(len(postsamps[0]))]).T + samples_1sigma = filter(lambda sample: np.all(onesig_bounds[0] <= sample) and np.all(sample <= onesig_bounds[1]), postsamps) + samples_1sigma_down = list(samples_1sigma)[::downfactor] + for sample in samples_1sigma_down: + plt.plot(datar_al[:,0].real, dict[model](sample).real, "r-", alpha=0.1, lw=1) + plt.title(r'Comparison of the MC fit data and the $1-\sigma$ error band') + plt.legend() + plt.xlabel('t') + plt.ylabel('h') + plt.show() + figband.savefig(fit_plot) + + +# In[162]: + + +if export: + with open(samples_file,'w') as file: + writer = csv.writer(file) + writer.writerow(labels) + writer.writerows(samps[::downfactor]) + diff --git a/code_new/RD_Dynesty_Fits/src/RD_Fits.py b/code_new/RD_Dynesty_Fits/src/RD_Fits.py new file mode 100755 index 0000000000000000000000000000000000000000..a8d13aac0567fe30ada2a645e23ee07072da0079 --- /dev/null +++ b/code_new/RD_Dynesty_Fits/src/RD_Fits.py @@ -0,0 +1,390 @@ +#!/usr/bin/env python +# coding: utf-8 + +# In[38]: + + +"""Generate ringdown templates in the time and perform parameter estimation on them. +""" + + +# In[1]: + + +#Import relevant modules, import data and all that +import time +import numpy as np +import corner +import matplotlib.pyplot as plt +from matplotlib.ticker import MaxNLocator +from matplotlib import rc +from configparser import ConfigParser +plt.rcParams.update({'font.size': 16.5}) + +from multiprocessing import Pool +import random +import dynesty +from dynesty import plotting as dyplot +from dynesty.utils import resample_equal +from dynesty import utils as dyfunc +import os +import argparse +import scipy.optimize as optimization +from scipy.optimize import minimize +import rdown as rd +import rdown_pe as rd_pe +import rdown_utilities as rd_ut +import read_data as rdata + + +# In[2]: + + +## Loading and running data tested with NR data +## Loading and running data tested with Mock data + + +# In[3]: + + +# Cell that calls the arguments from your 'config.ini' file. +try: + parser = argparse.ArgumentParser(description="Simple argument parser") + parser.add_argument("-c", action="store", dest="config_file") + result = parser.parse_args() + config_file=result.config_file + parser = ConfigParser() + parser.read(config_file) + parser.sections() +except SystemExit: + parser = ConfigParser() + parser.read('./run_0_mock/config_n0_to_1_mock.ini') + parser.sections() + pass + + +# In[4]: + + +# Load variables from config file +(simulation_path_1,simulation_path_2, metadata_file , simulation_number, output_folder, + export, overwrite, sampler,nr_code, nbcores,tshift,tend,t_align, + nmax , npoints, model, error_str, fitnoise, l_int, index_mass,index_spin, +error_type, error_val, af, mf,tau_var_str,nm_mock)=rdata.read_config_file(parser) + + +# In[5]: + + +# Show configuration options +dim = nmax+1 +ndim = 4*dim +numbins = 32 #corner plot parameter - how many bins you want + +print('model:',model) +print('nmax:',nmax) +print('nm_mock:',nm_mock) +print('tshift:',tshift) +print('error:', error_str) +print('error value:',error_val) +print('export:',export) +print('nr code:',nr_code) +print('fit noise:',fitnoise) + + +# In[6]: + + +# Create output directories +if not os.path.exists(output_folder): + os.mkdir(output_folder) + print("Directory " , output_folder , " Created ") + +if nr_code == 'Mock-data': + nm_mock_str = 'rec_with'+parser.get('rd-mock-parameters','nm_mock')+'_' +else: + nm_mock_str='' + +if error_str: + output_folder_1=(output_folder+'/'+model+'-nmax'+str(nmax)+'_'+nm_mock_str+str(error_str)+'_'+str(error_type)+'_fitnoise_'+str(fitnoise)) +else: + output_folder_1=output_folder+'/'+model+'-nmax'+str(nmax)+'_'+nm_mock_str+str(error_str)+'_'+'fitnoise_'+str(fitnoise) + +if not os.path.exists(output_folder_1): + os.mkdir(output_folder_1) + print("Directory " , output_folder_1 , " Created ") + + +# In[7]: + + +# Define output files +pars = [simulation_number,model,nmax,tshift,npoints] +corner_plot = rdata.create_output_files(output_folder_1,pars,'corner_plot') +corner_plot_extra = rdata.create_output_files(output_folder_1,pars,'corner_plot_extra') +diagnosis_plot = rdata.create_output_files(output_folder_1,pars,'diagnosis') +fit_plot = rdata.create_output_files(output_folder_1,pars,'fit') +samples_file = rdata.create_output_files(output_folder_1,pars,'post_samples') +results_file = rdata.create_output_files(output_folder_1,pars,'sampler_results') +sumary_data = rdata.create_output_files(output_folder_1,pars,'log_z') +best_data = rdata.create_output_files(output_folder_1,pars,'best_vals') + +files = [corner_plot,corner_plot_extra,diagnosis_plot,fit_plot,samples_file,results_file,sumary_data,best_data] + + +# In[8]: + + +# Remove old files if overwrite = True +if overwrite: + rd_ut.rm_files(files) + + +# In[46]: + + +#Load NR data, align in time and resize. Plot real part and amplitude. Finally compute the mismatch and the snr estimate +data = rdata.read_data(nr_code,simulation_path_1,RD=True,tshift=tshift,tend = tend,metadata_file=metadata_file,parser=parser) +data_l = rdata.read_data(nr_code,simulation_path_2,RD=True,tshift=tshift,tend = tend,metadata_file=metadata_file,parser=parser) +data_r, data_lr = rdata.nr_resize(data,data_l,tshift=tshift,tend=tend) +times_rd = data_r[:,0] + +plt.figure(figsize = (12, 8)) +plt.plot(times_rd, data_r[:,1].real, "r", alpha=0.3, lw=3, label=r'$Lev6$: real') +plt.plot(times_rd, np.sqrt((data_r[:,1].real)**2+(data_r[:,1].imag)**2), "r", alpha=0.3, lw=3, label=r'$Lev5\,amp$') +plt.plot(times_rd, data_lr[:,1].real, "b", alpha=0.3, lw=3, label=r'$Lev5: real$') +plt.plot(times_rd, np.sqrt((data_lr[:,1].real)**2+(data_lr[:,1].imag)**2), "b", alpha=0.3, lw=3, label=r'$Lev5\,amp$') +if error_str and error_val==0: + error = np.sqrt(data_r[:,1]*data_r[:,1]-2*data_r[:,1]*data_lr[:,1]+data_lr[:,1]*data_lr[:,1]) + error_est=np.sqrt(error.imag**2+error.real**2) + plt.plot(times_rd, error_est, "g", alpha=0.3, lw=2, label='error') +plt.legend() + +mismatch=1-rd_ut.EasyMatchT(times_rd,data_r[:,1],data_lr[:,1],tshift,tend) +error=np.sqrt(2*mismatch) +print('error estimate:',error) +print('mismatch:', mismatch) +print('snr:', rd_ut.EasySNRT(times_rd,data_r[:,1],data_lr[:,1],tshift,tend)/error**2) + + +# In[47]: + + +# Phase alignement +if parser.has_option('rd-model','phase_alignment'): + phase_alignment=eval(parser.get('rd-model','phase_alignment')) +else: + phase_alignment=False + +if phase_alignment: + datar_al = rdata.phase_align(data_r,data_lr) + gwdatanew5 = data_lr[:,1] + gwdatanew = datar_al[:,1] + timesrd_final = datar_al[:,0] + mismatch=1-rd_ut.EasyMatchT(timesrd_final,gwdatanew,gwdatanew5,tshift,tend) + error=np.sqrt(2*mismatch) + print('error estimate:',error) + print('mismatch:', mismatch) + print('snr:', rd_ut.EasySNRT(timesrd_final,gwdatanew,gwdatanew5,tshift,tend)/error) + if error_str: + error = np.sqrt(gwdatanew*gwdatanew-2*gwdatanew*gwdatanew5+gwdatanew5*gwdatanew5) + error_est=np.sqrt(error.imag**2+error.real**2) + else : + error = 1 +else: + datar_al = data_r + timesrd_final = datar_al[:,0] + +#Test the new interpolated data +if error_str and error_val==0: + plt.figure(figsize = (12, 8)) + plt.plot(timesrd_final, datar_al[:,1].real, "r", alpha=0.3, lw=2, label='Original') + plt.plot(timesrd_final, data_lr[:,1].real, "b", alpha=0.3, lw=2, label='Aligned') + plt.plot(timesrd_final, error_est, "b", alpha=0.3, lw=2, label='error') + plt.legend() + + +# In[48]: + + +# Define your noise depending on the noise configuration. Load priors and setup the likelihood with rd_pe.Ringdown_PE. +if error_str and error_val==0: + error_final = error_est + norm_factor = 100*len(error_final)/2*np.log(2*np.pi) +elif error_str and error_val!=0: + datar_al[:,1]+=random.uniform(0, error_val) + datar_al[:,1]+=1j*random.uniform(0, error_val) + error_tsh = error_val + error_final=(error_tsh.real**2+error_tsh.imag**2) + norm_factor = 0 +else: + error_tsh=1 + error_final=(error_tsh.real**2+error_tsh.imag**2) + norm_factor = 0 + +priors = rd_pe.load_priors(model,parser,nmax,fitnoise=fitnoise) +rdown=rd.Ringdown_Spectrum(mf,af,2,2,n=nmax,s=-2,time=timesrd_final) +rdown_pe = rd_pe.Ringdown_PE(rdown,datar_al,dim,priors,errors2=error_final,norm_factor=norm_factor,model=model,l_int=l_int) + + +# In[49]: + + +# Get a first estimate by trying to fit the data. +nll = lambda *args: -rdown_pe.log_likelihood(*args) +if model == 'w-tau-fixed-m-af': + if fitnoise: + initial = np.concatenate((np.ones(2*dim),[0.8,0.9,1])) + soln = minimize(nll, initial,bounds=priors) + vars_ml=soln.x + else: + initial = np.concatenate((np.ones(2*dim),[0.8,0.9])) + soln = minimize(nll, initial,bounds=priors) + vars_ml=soln.x +elif model == 'w-tau-fixed': + if fitnoise: + initial = np.concatenate((np.ones(2*dim),[0.2])) + soln = minimize(nll, initial,bounds=priors) + vars_ml=soln.x + else: + initial = np.ones(2*dim) + soln = minimize(nll, initial,bounds=priors) + vars_ml=soln.x +else: + if fitnoise: + initial = np.concatenate((np.ones(ndim),[1])) + soln = minimize(nll, initial,bounds=priors) + vars_ml=soln.x + else: + initial = np.ones(ndim) + soln = minimize(nll, initial,bounds=priors) + vars_ml=soln.x +print("best fit pars from fit: ",vars_ml) + + +# In[50]: + + +mypool = Pool(nbcores) +mypool.size = nbcores + +start = time.process_time() +f2=dynesty.NestedSampler(rdown_pe.log_likelihood,rdown_pe.prior_transform, len(priors), nlive=npoints,sample=sampler,pool=mypool) +if parser.has_option('setup','dlogz'): + dlogz=np.float(parser.get('setup','dlogz')) + f2.run_nested(dlogz=dlogz,print_progress=False) +else: + f2.run_nested(print_progress=False) + +print(time.process_time() - start) + + +# In[52]: + + +res = f2.results +res.samples_u.shape +res.summary() +samps=f2.results.samples +postsamps = rd_ut.posterior_samples(f2) +samps_tr=np.transpose(samps) +half_points=int(round((len(samps_tr[0])/1.25))) +evidence = res.logz[-1] +evidence_error = res.logzerr[-1] +if export: + rd_ut.save_object(res, results_file) + + +# In[53]: + + +pars = nmax,model,samps_tr, half_points +npamps = rd_ut.get_best_amps(pars,parser=parser,nr_code=nr_code) + + +# In[54]: + + +if export: + pars = simulation_number, nmax, tshift, evidence, evidence_error + rd_ut.export_logz_files(sumary_data,pars) + + +# In[55]: + + +labels = rd_ut.define_labels(dim,model,fitnoise) +if export: + pars = tshift, len(priors), labels + rd_ut.export_bestvals_files(best_data,postsamps,pars) + + +# In[56]: + + +w, tau = rdown.QNM_spectrum() +pars = w, tau, mf, af, npamps +truths = rd_ut.get_truths(model,pars,fitnoise) + + +# In[57]: + + +fg=corner.corner(postsamps,quantiles=[0.05,0.5,0.95],show_titles=True,max_n_ticks = 4,bins=50,truths=truths,labels=labels,truth_color='red') +plt.show() +if export: + fg.savefig(corner_plot, format = 'png', bbox_inches = 'tight') + + +# In[58]: + + +from importlib import reload +reload(rd_ut) +if model == 'w-tau-fixed-m-af' and export == True: + truths=np.concatenate((w,tau)) + labels_mf = np.concatenate((w_lab,tau_lab)) + new_samples = rd_ut.convert_m_af_2_w_tau_post(res,fitnoise=False) + figure = corner.corner(new_samples,truths=truths,quantiles=[0.05,0.95],labels=labels_mf,smooth=True,color='b',truth_color='r',show_titles=True) + figure.savefig(corner_plot_extra, format = 'png', bbox_inches = 'tight') + + +# In[151]: + + +#lnz_truth = ndim * -np.log(2 * 10.) # analytic evidence solution +fig, axes = dyplot.runplot(res) +fig.tight_layout() +if export: + fig.savefig(diagnosis_plot, format = 'png', dpi = 384, bbox_inches = 'tight') + + +# In[166]: + + +if export: + dict = {'w-tau':rdown.rd_model_wtau , 'w-q': rdown.rd_model_wq, 'w-tau-fixed':rdown.rd_model_wtau_fixed,'w-tau-fixed-m-af': rdown.rd_model_wtau_m_af} + figband = plt.figure(figsize = (12, 9)) + plt.plot(datar_al[:,0].real,datar_al[:,1].real, "green", alpha=0.9, lw=3, label=r'$res_{240}$') + onesig_bounds = np.array([np.percentile(postsamps[:, i], [5, 95]) for i in range(len(postsamps[0]))]).T + samples_1sigma = filter(lambda sample: np.all(onesig_bounds[0] <= sample) and np.all(sample <= onesig_bounds[1]), postsamps) + samples_1sigma_down = list(samples_1sigma)[::downfactor] + for sample in samples_1sigma_down: + plt.plot(datar_al[:,0].real, dict[model](sample).real, "r-", alpha=0.1, lw=1) + plt.title(r'Comparison of the MC fit data and the $1-\sigma$ error band') + plt.legend() + plt.xlabel('t') + plt.ylabel('h') + plt.show() + figband.savefig(fit_plot) + + +# In[162]: + + +if export: + with open(samples_file,'w') as file: + writer = csv.writer(file) + writer.writerow(labels) + writer.writerows(samps[::downfactor]) + diff --git a/code_new/RD_Dynesty_Fits/src/__init__.py b/code_new/RD_Dynesty_Fits/src/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..8b137891791fe96927ad78e64b0aad7bded08bdc --- /dev/null +++ b/code_new/RD_Dynesty_Fits/src/__init__.py @@ -0,0 +1 @@ + diff --git a/code_new/RD_Dynesty_Fits/src/rdown.py b/code_new/RD_Dynesty_Fits/src/rdown.py new file mode 100644 index 0000000000000000000000000000000000000000..1357ccbf98a454670c79fb49574d7fe1447e243a --- /dev/null +++ b/code_new/RD_Dynesty_Fits/src/rdown.py @@ -0,0 +1,208 @@ +# Copyright (C) 2021 Xisco Jimenez Forteza +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + +# +# ============================================================================= +# +# Preamble +# +# ============================================================================= +# +# Module to generate RD waveforms. + +import numpy as np +import qnm +import os + +f_fpars= [[2.95845, -2.58697, 0.0533469], [2.12539, -1.78054, 0.0865503], [1.74755, -1.44776, 0.123666], [1.78287, -1.53203, 0.129475], [2.04028, -1.83224, 0.112497]] +q_fpars=[[0.584077, 1.52053, -0.480658], [0.00561441, 0.630715, -0.432664], [-0.197965, 0.515956, -0.369706], [-0.275097, 0.455691, -0.331543], [-0.287596, 0.398514, -0.309799]] + + +c=2.99792458*10**8;G=6.67259*10**(-11);MS=1.9885*10**30; +class Ringdown_Spectrum: + """RDown model generator""" + def __init__(self,mf,af,l,m,n=4,s=-2,time=[],fixed=False,qnm_model='berti'): + self.mf = mf + self.af = af + self.l = l + self.m = m + self.n = n + self.time = time + self.grav_220 = [qnm.modes_cache(s=s,l=self.l,m=self.m,n=i) for i in range (0,self.n+1)] + self.dim = self.n+1 + self.fixed = fixed + self.qnm_model = qnm_model + dict_omega = {'berti': self.QNM_Berti , 'qnm': self.QNM_spectrum} + dic = {'w-tau':self.rd_model_wtau , 'w-q': self.rd_model_wq, 'w-tau-fixed':self.rd_model_wtau_fixed,'w-tau-fixed-m-af': self.rd_model_wtau_m_af} + + if len(self.time)==0: + self.time = np.arange(0,100,0.1) + + if self.fixed: + omegas_new=np.asarray([self.grav_220[i](a=self.af)[0] for i in range (0,self.dim)]) + self.w = (np.real(omegas_new))/self.mf + self.tau=-1/(np.imag(omegas_new))*self.mf + + + def QNM_spectrum(self): + """ It computes the RD frequencies and damping times in NR units. + """ + omegas_new=np.asarray([self.grav_220[i](a=self.af)[0] for i in range (0,self.n+1)]) + w_m_a = (np.real(omegas_new))/self.mf + tau_m_a=-1/(np.imag(omegas_new))*self.mf + + return (w_m_a, tau_m_a) + + def QNM_Berti(self,rdowndata): + """ It computes the RD frequencies and damping times in NR units. + """ + position=np.argmax(rdowndata[0,0] >= (self.af)) + #w_m_a=f1+f2*(1-af)**f3 + w_m_a=[None]*(self.n+1) + tau_ma_a=[None]*(self.n+1) + + for i in range(self.n+1): + qnm=rdowndata[i,1:3,position] + w_m_a[i] = qnm[0]/self.mf + tau_ma_a[i] = -1/(qnm[1])*self.mf + + return w_m_a, tau_ma_a + + + def w_fpars_Berti(self,n): + return f_fpars[n] + + def tau_qpars_Berti(self,n): + return q_fpars[n] + + def mass_from_wtau(self,n,w,tau): + f1,f2,f3 = w_fpars_Berti(n) + q1,q2,q3 = tau_qpars_Berti(n) + res=(f1 + f2*(2**(-1/q3)*((-2*q1 + w*tau)/q2)**(1/q3))**f3)/w + return res + + def spin_from_wtau(self,n,w,tau): + f1,f2,f3 = w_fpars_Berti(n) + q1,q2,q3 = tau_qpars_Berti(n) + res=1 - 2**(-1/q3)*((-2*q1 + w*tau)/q2)**(1/q3) + return res + + def mass_from_wtau_loop(self,w,tau,l,m): + res=[None]*dim + for n in range (0,dim): + f1,f2,f3 = w_fpars_Berti(n) + q1,q2,q3 = tau_qpars_Berti(n) + res[n]=(f1 + f2*(2**(-1/q3)*((-2*q1 + w[n]*tau[n])/q2)**(1/q3))**f3)/w[n] + return res + + def spin_from_wtau_loop(self,w,tau,l,m): + res=[None]*dim + for n in range (0,dim): + f1,f2,f3 = w_fpars_Berti(n) + q1,q2,q3 = tau_qpars_Berti(n) + res[n]= 1 - 2**(-1/q3)*((-2*q1 + w[n]*tau[n])/q2)**(1/q3) + return res + + + def rd_model_wtau(self,theta): + """RD model parametrized with the damping time tau. + """ + assert int(len(theta)/4) == self.dim, 'Please recheck your n and parameters' + + wvars = theta[ : (self.dim)] + tvars = theta[(self.dim) : 2*(self.dim)] + xvars = theta[2*(self.dim) : 3*(self.dim)] + yvars = theta[3*(self.dim) : ] + + ansatz = 0 + for i in range (0,self.dim): + ansatz += (xvars[i]*np.exp(1j*yvars[i]))*np.exp(-self.time/tvars[i]) * (np.cos(wvars[i]*self.time)-1j*np.sin(wvars[i]*self.time)) + # -1j to agree with SXS convention + return ansatz + + def rd_model_wtau_m_af(theta): + """RD model parametrized with the damping time tau and with the QNM spectrum fixd to GR. The QNM spectrum is given from the mass and spin. + """ + xvars = theta[ : (dim)] + yvars = theta[(dim) : 2*(dim)] + mass_vars = theta[index_mass] + spin_vars = theta[index_spin] + + w_m_a , tau_m_a = dict_omega[self.qnm_model](mass_vars,spin_vars,2,2) + + ansatz = 0 + for i in range (0,dim): + ansatz += (xvars[i]*np.exp(1j*yvars[i]))*np.exp(-timesrd_final_tsh/tau_m_a[i]) * (np.cos(w_m_a[i]*timesrd_final_tsh)-1j*np.sin(w_m_a[i]*timesrd_final_tsh)) + # -1j to agree with SXS convention + return ansatz + + def rd_model_wtau_fixed(theta): + """RD model parametrized with the damping time tau and with the QNM spectrum fixd to GR. + """ + xvars = theta[ : (dim)] + yvars = theta[(dim) : 2*(dim)] + + ansatz = 0 + for i in range (0,dim): + ansatz += (xvars[i]*np.exp(1j*yvars[i]))*np.exp(-timesrd_final_tsh/tau[i]) * (np.cos(w[i]*timesrd_final_tsh)-1j*np.sin(w[i]*timesrd_final_tsh)) + # -1j to agree with SXS convention + return ansatz + + def rd_model_wq(self,theta): + """RD model parametrized with the quality factor q. + """ + assert int(len(theta)/4) == self.dim, 'Please recheck your n and parameters' + + wvars = theta[ : (self.dim)] + qvars = theta[(self.dim) : 2*(self.dim)] + xvars = theta[2*(self.dim) : 3*(self.dim)] + yvars = theta[3*(self.dim) : ] + + ansatz = 0 + for i in range (0,self.dim): + ansatz += (xvars[i]*np.exp(1j*yvars[i]))*np.exp(-self.time*np.pi*wvars[i]/qvars[i])*(np.cos(wvars[i]*self.time)-1j*np.sin(wvars[i]*self.time)) + # -1j to agree with SXS convention + return ansatz + + def rd_model_wq_fixed(self,theta): + """RD model parametrized with the damping time tau and with the QNM spectrum fixd to GR. + """ + xvars = theta[ : (self.dim)] + yvars = theta[(self.dim) : 2*(self.dim)] + + ansatz = 0 + for i in range (0,self.dim): + ansatz += (xvars[i]*np.exp(1j*yvars[i]))*np.exp(-self.time/self.tau[i]) * (np.cos(self.w[i]*self.time)-1j*np.sin(self.w[i]*self.time)) + # -1j to agree with SXS convention + return ansatz + + + def rd_model_wq_m_a(self,theta): + """RD model parametrized with the damping time tau and with the QNM spectrum fixd to GR. The QNM spectrum is given from the mass and spin. + """ + xvars = theta[ : (self.dim)] + yvars = theta[(self.dim) : 2*(self.dim)] + mass_vars = theta[-2] + spin_vars = theta[-1] + + w_m_a , tau_m_a = QNM_spectrum() + + ansatz = 0 + for i in range (0,dim): + ansatz += (xvars[i]*np.exp(1j*yvars[i]))*np.exp(-timesrd_final_tsh/tau_m_a[i]) * (np.cos(w_m_a[i]*timesrd_final_tsh)-1j*np.sin(w_m_a[i]*timesrd_final_tsh)) + # -1j to agree with SXS convention + return ansatz \ No newline at end of file diff --git a/code_new/RD_Dynesty_Fits/src/rdown_pe.py b/code_new/RD_Dynesty_Fits/src/rdown_pe.py new file mode 100644 index 0000000000000000000000000000000000000000..c92e073cac48d68b9fb46fc44a03b6e1c2c8af65 --- /dev/null +++ b/code_new/RD_Dynesty_Fits/src/rdown_pe.py @@ -0,0 +1,191 @@ +# Copyright (C) 2021 Xisco Jimenez Forteza +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + +# +# ============================================================================= +# +# Preamble +# +# ============================================================================= +# +# Module to run PE on RD data +import random +from multiprocessing import Pool +import dynesty +import numpy as np +import rdown + +class Ringdown_PE: + def __init__(self,rdown_fun,data,dim,priors,errors2=1,theta=[],model='w-tau',norm_factor=0,l_int=0): + self.dim = dim + self.rdown_fun = rdown_fun + self.times = data[:,0] + self.datare = data[:,1].real + self.dataim = data[:,1].imag + self.priors = priors + self.priors_min = priors[:,0] + self.priors_max = priors[:,1] + self.prior_dim = len(priors) + self.errors2 = errors2 + self.norm_factor = norm_factor + self.model = model + self.l_int = l_int + self.theta = theta + self.dict = {'w-tau':rdown_fun.rd_model_wtau , 'w-q': rdown_fun.rd_model_wq, 'w-tau-fixed':rdown_fun.rd_model_wtau_fixed,'w-tau-fixed-m-af': rdown_fun.rd_model_wtau_m_af} + + #def log_likelihood(self,theta,sigma=1): + # """chi2 likelihood. + # """ + # modelev = dict[model](theta) + # result = -np.sum(((gwdatanew_re_tsh - modelev.real)**2+(gwdatanew_im_tsh - modelev.imag)**2)/(2*theta[-1]*error_final)) + # if np.isnan(result): + # return -np.inf + # return result + + def log_likelihood(self,theta,sigma=1): + """chi2 likelihood. + """ + modelev = self.dict[self.model](theta) + modelevre= modelev.real + modelevim= modelev.imag + + sigma2 = self.errors2 + self.l_int*(self.datare** 2+self.dataim**2) * np.exp(2 * theta[-1]) + + result = -0.5*np.sum(((self.datare - modelevre)**2+(self.dataim - modelevim)**2)/sigma2+self.l_int*(np.log(2*np.pi*sigma2)))-self.l_int*self.norm_factor + + if np.isnan(result): + return -np.inf + return result + + + def prior_transform(self,cube): + """RD uniform priors. The values for priors_min and priors_max must be given out of this function. + """ + for i in range(self.prior_dim): + cube[i] = self.priors_min[i]+ cube[i]*(self.priors_max[i]-self.priors_min[i]) + return cube + +def load_priors(model,config_parser,nmax,fitnoise=True): + # loading priors + if model == 'w-q': + tau_var_str='q' + else: + tau_var_str='tau' + + if model == 'w-tau': + w_mins=np.empty(nmax+1) + w_maxs=np.empty(nmax+1) + tau_mins=np.empty(nmax+1) + tau_maxs=np.empty(nmax+1) + a_mins=np.empty(nmax+1) + a_maxs=np.empty(nmax+1) + ph_mins=np.empty(nmax+1) + ph_maxs=np.empty(nmax+1) + + for i in range(nmax+1): + wp_min=config_parser.get('prior-w'+str(i),'w'+str(i)+'_min') + w_mins[i] = np.float(wp_min) + + wp_max=config_parser.get('prior-w'+str(i),'w'+str(i)+'_max') + w_maxs[i] = np.float(wp_max) + + taup_min=config_parser.get('prior-'+tau_var_str+str(i),tau_var_str+str(i)+'_min') + tau_mins[i] = np.float(taup_min) + + taup_max=config_parser.get('prior-'+tau_var_str+str(i),tau_var_str+str(i)+'_max') + tau_maxs[i] = np.float(taup_max) + + amp0_min=config_parser.get('prior-amp'+str(i),'amp'+str(i)+'_min') + a_mins[i] = np.float(amp0_min) + + amp1_max=config_parser.get('prior-amp'+str(i),'amp'+str(i)+'_max') + a_maxs[i] = np.float(amp1_max) + + phase_min=config_parser.get('prior-phase'+str(i),'phase'+str(i)+'_min') + ph_mins[i] = np.float(phase_min)*2*np.pi + + phase_max=config_parser.get('prior-phase'+str(i),'phase'+str(i)+'_max') + ph_maxs[i] = np.float(phase_max)*2*np.pi + + priors_min = np.concatenate((w_mins,tau_mins,a_mins,ph_mins)) + priors_max = np.concatenate((w_maxs,tau_maxs,a_maxs,ph_maxs)) + prior_dim = len(priors_min) + priors=np.column_stack((priors_min,priors_max)) + + if model == 'w-tau-fixed': + a_mins=np.empty(nmax+1) + a_maxs=np.empty(nmax+1) + ph_mins=np.empty(nmax+1) + ph_maxs=np.empty(nmax+1) + + for i in range(nmax+1): + amp0_min=config_parser.get('prior-amp'+str(i),'amp'+str(i)+'_min') + a_mins[i] = np.float(amp0_min) + + amp1_max=config_parser.get('prior-amp'+str(i),'amp'+str(i)+'_max') + a_maxs[i] = np.float(amp1_max) + + phase_min=config_parser.get('prior-phase'+str(i),'phase'+str(i)+'_min') + ph_mins[i] = np.float(phase_min)*2*np.pi + + phase_max=config_parser.get('prior-phase'+str(i),'phase'+str(i)+'_max') + ph_maxs[i] = np.float(phase_max)*2*np.pi + + + priors_min = np.concatenate((a_mins,ph_mins)) + priors_max = np.concatenate((a_maxs,ph_maxs)) + prior_dim = len(priors_min) + priors=np.column_stack((priors_min,priors_max)) + + elif model == 'w-tau-fixed-m-af': + a_mins=np.empty(nmax+1) + a_maxs=np.empty(nmax+1) + ph_mins=np.empty(nmax+1) + ph_maxs=np.empty(nmax+1) + + for i in range(nmax+1): + amp0_min=config_parser.get('prior-amp'+str(i),'amp'+str(i)+'_min') + a_mins[i] = np.float(amp0_min) + + amp1_max=config_parser.get('prior-amp'+str(i),'amp'+str(i)+'_max') + a_maxs[i] = np.float(amp1_max) + + phase_min=config_parser.get('prior-phase'+str(i),'phase'+str(i)+'_min') + ph_mins[i] = np.float(phase_min)*2*np.pi + + phase_max=config_parser.get('prior-phase'+str(i),'phase'+str(i)+'_max') + ph_maxs[i] = np.float(phase_max)*2*np.pi + + mass_min=[np.float(config_parser.get('prior-mass','mass_min'))] + mass_max=[np.float(config_parser.get('prior-mass','mass_max'))] + spin_min=[np.float(config_parser.get('prior-spin','spin_min'))] + spin_max=[np.float(config_parser.get('prior-spin','spin_max'))] + priors_min = np.concatenate((a_mins,ph_mins,mass_min,spin_min)) + priors_max = np.concatenate((a_maxs,ph_maxs,mass_max,spin_max)) + prior_dim = len(priors_min) + priors=np.column_stack((priors_min,priors_max)) + + + if fitnoise: + priors_fit_min=[np.float(config_parser.get('prior-noise','noise_min'))] + priors_fit_max=[np.float(config_parser.get('prior-noise','noise_max'))] + priors_min = np.concatenate((priors_min,priors_fit_min)) + priors_max = np.concatenate((priors_max,priors_fit_max)) + priors=np.column_stack((priors_min,priors_max)) + prior_dim = len(priors_min) + + return priors \ No newline at end of file diff --git a/code_new/RD_Dynesty_Fits/src/rdown_utilities.py b/code_new/RD_Dynesty_Fits/src/rdown_utilities.py new file mode 100644 index 0000000000000000000000000000000000000000..c4a5b95c1c26beb418d2457fbd2a2b09212778c3 --- /dev/null +++ b/code_new/RD_Dynesty_Fits/src/rdown_utilities.py @@ -0,0 +1,318 @@ +# Copyright (C) 2021 Xisco Jimenez Forteza +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + +# +# ============================================================================= +# +# Preamble +# +# ============================================================================= +# +# Module to run PE on RD data +import numpy as np +from dynesty.utils import resample_equal +from dynesty import utils as dyfunc +import os +import csv +import pandas as pd +import pickle + +def posterior_samples(sampler): + """ + Returns posterior samples from nested samples and weights + given by dynsety sampler + """ + + dynesty_samples = sampler.results['samples'] + wt = np.exp(sampler.results['logwt'] - + sampler.results['logz'][-1]) + # Make sure that sum of weights equal to 1 + weights = wt/np.sum(wt) + posterior_dynesty = dyfunc.resample_equal(dynesty_samples, weights) + return posterior_dynesty + +def FFT_FreqBins(times): + Len = len(times) + DeltaT = times[-1]- times[0] + dt = DeltaT/(Len-1) + dnu = 1/(Len*dt) + maxfreq = 1/(2*dt) + add = dnu/4 + + p = np.arange(0.0,maxfreq+add,dnu) + m = np.arange(p[-1]-(2*maxfreq)+dnu,-dnu/2+add,dnu) + res=np.concatenate((p,m)) + + return res + +def hFromPsi4FFI(tpsi4,f0): + + timecheck1=tpsi4[-2,0]-tpsi4[-1,0] + timecheck2=tpsi4[1,0]-tpsi4[0,0] + + if np.abs(timecheck1-timecheck2)>=0.0001: + print("The data might not be equally sampled!!") + + times,data= tpsi4[:,0],tpsi4[:,1] + + freqs = FT_FreqBins(xaxis.real).real + position = np.argmax(freqs >= f0) + freqs[:position]=f0*np.ones(len(freqs[:position])) + freqs=2*np.pi*freqs + + fdata=fft(data) + len(myTable)*ifft(- fdata/floor**2); + np.stack((times,data)).T + + +def twopoint_autocovariance(t,n): + """ It computes the two-point autocovariance function. + """ + dt=t[1]-t[0] + res = np.zeros(len(n)) + taus = np.zeros(len(n)) + for tau in range(0,int(len(n)/2)): + ntau=np.roll(n, tau) + taus[tau] = t[tau] + res[tau]=np.sum(n*ntau).real + return (taus[:int(len(n)/2)],res[:int(len(n)/2)]) + +def save_object(obj, filename): + with open(filename, 'wb') as output: # Overwrites any existing file. + pickle.dump(obj, output, pickle.HIGHEST_PROTOCOL) + + +def EasyMatchT(t,h1,h2,tmin,tmax): + """ It computes the time-domain match for (h1|h2) complex waveforms. + """ + pos = np.argmax(t >= (tmin)); + + h1red=h1[pos:]; + h2red=h2[pos:]; + + norm1=np.sum(np.abs(h1red)**2) + norm2=np.sum(np.abs(h2red)**2) + + myTable=h1red*np.conjugate(h2red) + res=((np.sum(myTable)/np.sqrt(norm1*norm2))).real + + return res + +def EasySNRT(t,h1,h2,tmin,tmax): + """ It computes the time-domain snr for (h1|h2) complex waveforms. + """ + pos = np.argmax(t >= (tmin)); + + h1red=h1[pos:]; + h2red=h2[pos:]; + + myTable=h1red*np.conjugate(h2red) + res=2*np.sqrt((np.sum(myTable)).real) + + return res + +def FindTmaximum(y): + """ It determines the maximum absolute value of the complex waveform. + """ + absval = np.sqrt(y[:,1]*y[:,1]+y[:,2]*y[:,2]) + vmax=np.max(absval) + index = np.argmax(absval == vmax) + timemax=y[index,0] + + return timemax + +def export_logz_files(output_file,pars): + sim_num, nmax, tshift, evidence, evidence_error = pars + + """ + Generate the logz.csv files you want to export the data to. + file_type must be one of this options: [corner_plot,corner_plot_extra,diagnosis,fit,post_samples,sampler_results,log_z] + """ + + summary_titles=['n','id','t_shift','dlogz','dlogz_err'] + if os.path.exists(output_file): + outvalues = np.array([[nmax, sim_num, tshift, evidence,evidence_error]]) + else: + outvalues = np.array([summary_titles,[nmax, sim_num, tshift, evidence,evidence_error]]) + + with open(output_file, 'a') as file: + writer = csv.writer(file) + if (outvalues.shape)[0]>1 : + writer.writerows(outvalues) + else: + writer.writerow(outvalues[0]) + + return + +def export_bestvals_files(best_data_file,postsamps,pars): + + tshift, lenpriors, labels = pars + + sigma_vars_m = np.empty(lenpriors) + sigma_vars_p = np.empty(lenpriors) + sigma_vars = np.empty(lenpriors) + sigma_vars_ml = np.empty(lenpriors) + for i in range(lenpriors): + amps_aux = postsamps[:,i] + sigma_vars_m[i] = np.quantile(amps_aux, 0.05) + sigma_vars[i] = np.quantile(amps_aux, 0.5) + sigma_vars_ml[i] = postsamps[-1,i] + sigma_vars_p[i] = np.quantile(amps_aux, 0.95) + + sigma_vars_all = [sigma_vars,sigma_vars_ml,sigma_vars_m,sigma_vars_p] + sigma_vars_all=np.stack([sigma_vars,sigma_vars_ml,sigma_vars_m,sigma_vars_p], axis=0) + + key =['max val','max val ml','lower bound','higher bound'] + dfslist = [pd.DataFrame(np.concatenate(([tshift],sigma_vars_all[i])).reshape((-1,lenpriors+1)), columns=np.concatenate((['tshift'],labels)), index = [key[i]]) for i in range(4)] + df2 = pd.concat(dfslist) + if os.path.exists(best_data_file): + df2.to_csv(best_data_file, mode='a', header=False,index = True) + else: + df2.to_csv(best_data_file, index = True) + + + +def define_labels(dim,model,fitnoise): + wstr = r'$\omega_' + + if model == 'w-tau': + taustr = r'$\tau_' + elif model == 'w-q': + taustr = r'$q_' + elif model == 'w-tau-fixed': + taustr = r'$dumb_var}' + elif model == 'w-tau-fixed-m-af': + taustr = r'$\tau_' + + ampstr = r'$A_' + phasestr = r'$\phi_' + + w_lab = [None] * dim + tau_lab = [None] * dim + amp_lab = [None] * dim + pha_lab = [None] * dim + mass_lab = ['mass'] + spin_lab = ['spin'] + + for i in range(dim): + w_lab[i] = wstr+str(i)+'$' + tau_lab[i] = taustr+str(i)+'$' + amp_lab[i] = ampstr+str(i)+'$' + pha_lab[i] = phasestr+str(i)+'$' + + + labels = np.concatenate((w_lab,tau_lab,amp_lab,pha_lab)) + + if model=='w-tau-fixed': + labels = np.concatenate((amp_lab,pha_lab)) + + if model=='w-tau-fixed-m-af': + pha_lab[i] = phasestr+str(i)+'$' + + labels = np.concatenate((amp_lab,pha_lab,mass_lab,spin_lab)) + + if fitnoise: + noise_lab = ['noise'] + labels = np.concatenate((labels,noise_lab)) + + return labels + +def get_truths(model,pars,fitnoise): + w, tau, mf, af , npamps = pars + if model == 'w-q': + tau_val = np.pi*w*tau + truths = np.concatenate((w,tau_val,npamps)) + elif model == 'w-tau': + tau_val = tau + truths = np.concatenate((w,tau_val,npamps)) + elif model == 'w-tau-fixed': + truths = npamps + elif model == 'w-tau-fixed-m-af': + truths = np.concatenate((npamps,[mf],[af])) + + if fitnoise: + truths = np.concatenate((truths,[1])) + + return truths + +def get_best_amps(pars,parser=None,nr_code=None): + nmax,model,samps_tr,half_points = pars + + + if model=='w-tau-fixed': + rg = (nmax+1) + elif model=='w-tau-fixed': + rg = (nmax+1)+2 + else: + rg = (nmax+1)*2 + + + if model=='w-tau-fixed-a-mf': + npamps = np.empty((nmax+1)) + for i in range(0,(nmax+1)): + amps_aux = samps_tr[i+rg][half_points:-1] + npamps[i] = np.quantile(amps_aux, 0.5) + else : + npamps = np.empty((nmax+1)*2) + for i in range(0,(nmax+1)*2): + amps_aux = samps_tr[i][half_points:-1] + npamps[i] = np.quantile(amps_aux, 0.5) + + if nr_code == 'Mock-data': + nm_mock = parser.get('rd-mock-parameters','nm_mock') + nm_mock = np.int(nm_mock) + amp_mock=np.empty(nm_mock+1) + ph_mock=np.empty(nm_mock+1) + for i in range(nm_mock+1): + amp_mockp = parser.get('rd-mock-parameters','amp'+str(i)) + amp_mock[i] = np.float(amp_mockp) + ph_mockp=parser.get('rd-mock-parameters','phase'+str(i)) + ph_mock[i] = np.float(ph_mockp) + + npamps = np.concatenate((amp_mock,ph_mock)) + return npamps + +def convert_m_af_2_w_tau_post(res,fitnoise=False): + + samples_2=res.samples + samps=f2.results.samples + + if fitnoise: + fmass_spin=(samps.T)[-3:-1].T + else: + fmass_spin=(samps.T)[-2:].T + #fmass_spin=new_samples[-2:] + fmass_spin_dist=[None]*len(fmass_spin) + weight=np.exp(res.logwt - res.logz[-1]) + for i in range(len(fmass_spin)): + fmass_spin_dist[i]=np.concatenate(dict_omega[qnm_model](fmass_spin[i,0],fmass_spin[i,1],2,2)) + + fmass_spin_dist_v2=np.asarray(fmass_spin_dist) + new_samples = dyfunc.resample_equal(fmass_spin_dist_v2, weight) + + return new_samples + +def save_object(obj, filename): + with open(filename, 'wb') as output: # Overwrites any existing file. + pickle.dump(obj, output, pickle.HIGHEST_PROTOCOL) + +def rm_files(files): + """ rm all old files """ + for i in files: + if os.path.exists(i): + os.remove(i) + \ No newline at end of file diff --git a/code_new/RD_Dynesty_Fits/src/read_data.py b/code_new/RD_Dynesty_Fits/src/read_data.py new file mode 100644 index 0000000000000000000000000000000000000000..87185de6364a1b89cb9223329e31dc5bb3e58391 --- /dev/null +++ b/code_new/RD_Dynesty_Fits/src/read_data.py @@ -0,0 +1,344 @@ +# Copyright (C) 2021 Xisco Jimenez Forteza +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + +# +# ============================================================================= +# +# Preamble +# +# ============================================================================= +# +# Module to run PE on RD data +import numpy as np +import rdown_utilities as rd_ut +import romspline +import rdown as rd +import h5py +import json +from scipy import interpolate +from scipy.interpolate import interp1d + + +def read_data(nr_code,sim_path,mf=1,af=0,parser=None,RD=True,tshift=0,tend = 100,metadata_file=None): + if nr_code=='SXS': + gw = {} + gw = h5py.File(sim_path, 'r') + gw_data = gw["Extrapolated_N3.dir"]["Y_l2_m2.dat"] + times = gw_data[:,0] + + metadata = {} + with open(metadata_file) as file: + metadata = json.load(file) + + af = metadata['remnant_dimensionless_spin'][-1] + mf = metadata['remnant_mass'] + + tmax=rd_ut.FindTmaximum(gw_data[round(len(gw_data)/2):]) + times = times - tmax + + if RD: + position = np.argmax(times >= 0) + gw_data = gw_data[:,1][position:]+1j*gw_data[:,2][position:] + times = times[times >= 0] + + elif nr_code=='Maya': + dt=0.1 + gw = {} + gw = h5py.File(sim_path, 'r') + gw_sxs_bbh_0305_amp = np.asarray(gw['amp_l2_m2/Y'])[6:] + times_1 = np.asarray(gw['amp_l2_m2/X'])[6:] + gw_sxs_bbh_0305_amp_int = romspline.ReducedOrderSpline(times_1, gw_sxs_bbh_0305_amp) + gw_sxs_bbh_0305_pha = np.asarray(gw['phase_l2_m2/Y'])[6:] + times = np.asarray(gw['phase_l2_m2/X'])[6:] + gw_sxs_bbh_0305_pha_int = romspline.ReducedOrderSpline(times, gw_sxs_bbh_0305_pha) + + tmin=max(times_1[0],times[0]) + tmax=min(times_1[-1],times[-1]) + times=np.arange(tmin,tmax,dt) + amps=gw_sxs_bbh_0305_amp_int(times) + phs=gw_sxs_bbh_0305_pha_int(times) + gw_sxs_bbh_0305 = np.asarray([times,amps*np.cos(phs),amps*np.sin(phs)]).T + gw5_sxs_bbh_0305 = gw_sxs_bbh_0305 + + times = gw_sxs_bbh_0305[:,0] + tmax=rd_ut.FindTmaximum(gw_sxs_bbh_0305[round(len(gw_sxs_bbh_0305)/2):]) + times = times - tmax + + #times 6--> x axis of your data + times5 = gw5_sxs_bbh_0305[:,0] + tmax5=rd_ut.FindTmaximum(gw5_sxs_bbh_0305[round(len(gw_sxs_bbh_0305)/2):]) + times5 = times5 - tmax5 + #Select the data from 0 onwards + position = np.argmax( times >= (t_align)) + position5 = np.argmax(times5 >= (t_align)) + gw_sxs_bbh_0305rd=gw_sxs_bbh_0305[position+1:] + gw_sxs_bbh_0305rd5=gw5_sxs_bbh_0305[position5+1:] + timesrd=gw_sxs_bbh_0305[position:-1][:,0][:] + timesrd5=gw5_sxs_bbh_0305[position5:-1][:,0][:] + + elif nr_code=='LaZeV': + dt=0.1 + gw = {} + gw = h5py.File(simulation_path_1, 'r') + gw_sxs_bbh_0305_amp = np.asarray(gw['amp_l2_m2/Y'])[6:] + times_1 = np.asarray(gw['amp_l2_m2/X'])[6:] + gw_sxs_bbh_0305_amp_int = romspline.ReducedOrderSpline(times_1, gw_sxs_bbh_0305_amp) + gw_sxs_bbh_0305_pha = np.asarray(gw['phase_l2_m2/Y'])[6:] + times = np.asarray(gw['phase_l2_m2/X'])[6:] + gw_sxs_bbh_0305_pha_int = romspline.ReducedOrderSpline(times, gw_sxs_bbh_0305_pha) + + tmin=max(times_1[0],times[0]) + tmax=min(times_1[-1],times[-1]) + times=np.arange(tmin,tmax,dt) + amps=gw_sxs_bbh_0305_amp_int(times) + phs=gw_sxs_bbh_0305_pha_int(times) + gw_sxs_bbh_0305 = np.asarray([times,amps*np.cos(phs),amps*np.sin(phs)]).T + gw5_sxs_bbh_0305 = gw_sxs_bbh_0305 + + times = gw_sxs_bbh_0305[:,0] + tmax=rd_ut.FindTmaximum(gw_sxs_bbh_0305[round(len(gw_sxs_bbh_0305)/2):]) + times = times - tmax + + #times 6--> x axis of your data + times5 = gw5_sxs_bbh_0305[:,0] + tmax5=rd_ut.FindTmaximum(gw5_sxs_bbh_0305[round(len(gw_sxs_bbh_0305)/2):]) + times5 = times5 - tmax5 + + #Select the data from 0 onwards + position = np.argmax( times >= (t_align)) + position5 = np.argmax(times5 >= (t_align)) + gw_sxs_bbh_0305rd=gw_sxs_bbh_0305[position+1:] + gw_sxs_bbh_0305rd5=gw5_sxs_bbh_0305[position5+1:] + timesrd=gw_sxs_bbh_0305[position:-1][:,0][:] + timesrd5=gw5_sxs_bbh_0305[position5:-1][:,0][:] + + elif nr_code=='Mock-data': + times = np.arange(tshift,tend+10,0.1) + + nm_mock = parser.get('rd-mock-parameters','nm_mock') + nm_mock = np.int(nm_mock) + mf = parser.get('rd-mock-parameters','mf') + mf = np.float(mf) + af = np.float(parser.get('rd-mock-parameters','af')) + af = np.float(af) + + rdown=rd.Ringdown_Spectrum(mf,af,2,2,n=nm_mock,s=-2,time=times) + + w_mock=np.empty(nm_mock+1) + tau_mock=np.empty(nm_mock+1) + amp_mock=np.empty(nm_mock+1) + ph_mock=np.empty(nm_mock+1) + + for i in range(nm_mock+1): + wp_mock = parser.get('rd-mock-parameters','w'+str(i)) + w_mock[i] = np.float(wp_mock) + tp_mock=parser.get('rd-mock-parameters','tau'+str(i)) + tau_mock[i] = np.float(tp_mock) + amp_mockp = parser.get('rd-mock-parameters','amp'+str(i)) + amp_mock[i] = np.float(amp_mockp) + ph_mockp=parser.get('rd-mock-parameters','phase'+str(i)) + ph_mock[i] = np.float(ph_mockp) + + + pars = np.concatenate((w_mock,tau_mock,amp_mock,ph_mock)) + gw_data=rdown.rd_model_wtau(pars) + + return np.stack((times,gw_data)).T + +def nr_resize(data_1,data_2,tshift=0,tend=100): + times_1 = data_1[:,0].real + times_2 = data_2[:,0].real + data_1_re = data_1[:,1].real + data_1_im = data_1[:,1].imag + data_2_re = data_2[:,1].real + data_2_im = data_2[:,1].imag + + gwnew_re = interpolate.interp1d(times_1, data_1_re, kind = 'cubic') + gwnew_im = interpolate.interp1d(times_1, data_1_im, kind = 'cubic') + gwnew_re5 = interpolate.interp1d(times_2, data_2_re, kind = 'cubic') + gwnew_im5 = interpolate.interp1d(times_2, data_2_im, kind = 'cubic') + + if times_2[-1]>= times_1[-1]: + times_rd = times_1 + else: + times_rd = times_2 + + gwdatanew_re = gwnew_re(times_rd) + gwdatanew_im = gwnew_im(times_rd) + gwdatanew_re5 = gwnew_re5(times_rd) + gwdatanew_im5 = gwnew_im5(times_rd) + gwdatanew = gwdatanew_re + 1j*gwdatanew_im + gwdatanew5 = gwdatanew_re5 + 1j*gwdatanew_im5 + + position_in = np.argmax(times_rd >= tshift) + position_end = np.argmax(times_rd >= tend) + times_rd = times_rd[position_in:position_end] + gwdatanew = gwdatanew[position_in:position_end] + gwdatanew5 = gwdatanew5[position_in:position_end] + + return(np.stack((times_rd,gwdatanew)).T,np.stack((times_rd,gwdatanew5)).T) + + +def phase_align(data_1,data_2,t_align=0): + + #timesrd_final = data_1[:,0] + #phas = np.angle(data_1[:,1]) + #phas = np.unwrap(phas) + #phas5 = np.angle(data_2[:,1]) + #phas5 = np.unwrap(phas5) + #position = np.argmax(timesrd_final >= (t_align)) + #dphase = phas5[position]-phas[position] + + #gwdatanew = data_1[:,1]*np.exp(1j*dphase) + + + phas = np.angle(data_1[:,1]) + phas = np.unwrap(phas) + phas5 = np.angle(data_2[:,1]) + phas5 = np.unwrap(phas5) + position = np.argmax(data_1[:,0] >= (0)) + dphase = phas5[position]-phas[position] + gwdatanew = data_1[:,1]*np.exp(1j*dphase) + timesrd_final = data_1[:,0] + + return np.stack((timesrd_final,gwdatanew)).T + +def create_output_files(output_folder,pars,file_type): + sim_num, model, nmax, tshift, npoints = pars + + """ + Generate the output files you want to export the data to. + file_type must be one of this options: [corner_plot,corner_plot_extra,diagnosis,fit,post_samples,sampler_results,log_z] + """ + + if file_type=='corner_plot': + outfile = output_folder+'/Dynesty_'+str(sim_num)+'_'+model+'_nmax_'+str(nmax)+'_tshift_'+str(tshift)+'_'+str(npoints)+'corner_plot.png' + elif file_type=='corner_plot_extra': + outfile = output_folder+'/Dynesty_'+str(sim_num)+'_'+model+'_nmax_'+str(nmax)+'_tshift_'+str(tshift)+'_'+str(npoints)+'corner_plot_extra.png' + elif file_type=='diagnosis': + outfile = output_folder+'/Dynesty_diagnosis'+str(sim_num)+'_'+model+'_nmax_'+str(nmax)+'_tshift_'+str(tshift)+'_'+str(npoints)+'.png' + elif file_type=='fit': + outfile = output_folder+'/Fit_results_'+str(sim_num)+'tshift_'+str(tshift)+'_'+model+'_nmax_'+str(nmax)+'.png' + elif file_type=='post_samples': + outfile = output_folder+'/posterior_samples-'+str(sim_num)+'tshift_'+str(tshift)+'_'+model+'_nmax_'+str(nmax)+'.csv' + elif file_type=='sampler_results': + outfile = output_folder+'/results_'+str(sim_num)+'tshift_'+str(tshift)+'_'+model+'_nmax_'+str(nmax)+'.pkl' + elif file_type=='log_z': + outfile = output_folder+'/summary'+str(sim_num)+'_'+model+'_nmax_'+str(nmax)+'.csv' + elif file_type=='best_vals': + outfile = output_folder+'/best_values_'+str(sim_num)+'_'+model+'_nmax_'+str(nmax)+'.csv' + else: + print ('Something went wrong') + return + + return outfile + +def read_config_file(parser): + # Setup path and output folders + rootpath=parser.get('nr-paths','rootpath') + simulation_path_1 = parser.get('nr-paths','simulation_path_1') + + if parser.get('nr-paths','simulation_path_2'): + simulation_path_2 = parser.get('nr-paths','simulation_path_2') + else: + simulation_path_2 = simulation_path_1 + + metadata_file = parser.get('nr-paths','metadata_json') + simulation_number = parser.get('nr-paths','simulation_number') + simulation_number = np.int(simulation_number) + + output_folder = parser.get('output-folder','output-folder') + if parser.has_option('setup','export'): + export=eval(parser.get('setup','export')) + else: + export=True + + # Setup sampler and output options + overwrite = eval(parser.get('setup','overwrite')) + downfactor = np.int(parser.get('setup','plot_down_factor')) + sampler = parser.get('setup','sampler') + nr_code = parser.get('setup','nr_code') + if parser.has_option('setup','nb_cores'): + nbcores = np.int(parser.get('setup','nb_cores')) + else: + nbcores = 1 + + # time shift , end and align options + tshift=parser.get('time-setup','tshift') + tshift = np.float(tshift) + + tend=parser.get('time-setup','tend') + tend = np.float(tend) + + t_align=parser.get('time-setup','t_align') + t_align = np.float(t_align) + + # n-tones & nlive points + nmax=parser.get('n-tones','nmax') + nmax = np.int(nmax) + + npoints=parser.get('n-live-points','npoints') + npoints = np.int(npoints) + + # setup the RD model + model=parser.get('rd-model','model') + error_str = eval(parser.get('rd-model','error_str')) + fitnoise=eval(parser.get('rd-model','fit_noise')) + if fitnoise: + l_int=1 + index_mass=-3 + index_spin=-2 + # prior_dim = len(priors_min) + else: + index_mass=-2 + index_spin=-1 + l_int=0 + + if error_str: + error_val=np.float(parser.get('rd-model','error_val')) + if error_val==0: + error_type='' + else: + error_type=error_val + else: + error_type='False' + error_val =0 + + if nr_code == 'SXS': + metadata = {} + with open(metadata_file) as file: + metadata = json.load(file) + af = metadata['remnant_dimensionless_spin'][-1] + mf = metadata['remnant_mass'] + else: + mf = parser.get('rd-mock-parameters','mf') + mf = np.float(mf) + af = np.float(parser.get('rd-mock-parameters','af')) + af = np.float(af) + + if model == 'w-q': + tau_var_str='q' + else: + tau_var_str='tau' + + if nr_code == 'Mock-data': + nm_mock = int(parser.get('rd-mock-parameters','nm_mock')) + else: + nm_mock = None + + res = simulation_path_1,simulation_path_2, metadata_file , simulation_number, output_folder, export, overwrite, sampler,nr_code, nbcores,tshift,tend,t_align, nmax , npoints, model, error_str, fitnoise, l_int, index_mass,index_spin, error_type, error_val, af, mf,tau_var_str,nm_mock + return res \ No newline at end of file