diff --git a/cosmo_inference/notebooks/2D_cosmic_shear_configuration_plots/S8_om_sigma8_whisker.ipynb b/cosmo_inference/notebooks/2D_cosmic_shear_configuration_plots/S8_om_sigma8_whisker.ipynb new file mode 100644 index 00000000..f80ece0d --- /dev/null +++ b/cosmo_inference/notebooks/2D_cosmic_shear_configuration_plots/S8_om_sigma8_whisker.ipynb @@ -0,0 +1,510 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "3aee8492", + "metadata": {}, + "source": [ + "# Whisker plot\n", + "\n", + "This notebook plots the whisker plot of $S_8$, $\\Omega_m$ and $\\sigma_8$" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "889d7da8", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import sys\n", + "\n", + "# Trick to plot with tex\n", + "os.environ[\"LD_LIBRARY_PATH\"] = \"\"\n", + "os.environ[\"CONDA_PREFIX\"] = \"/home/guerrini/.conda/envs/sp_validation_3.11\"\n", + "\n", + "sys.path.append(\n", + " \"/n23data1/n06data/lgoh/scratch/UNIONS/cosmo_inference/notebooks/\"\n", + ")\n", + "\n", + "from getdist import plots, loadMCSamples\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "import seaborn as sns\n", + "import warnings\n", + "import sys\n", + "\n", + "sys.path.append(\"/home/guerrini/sp_validation/cosmo_inference/scripts\")\n", + "\n", + "import chain_postprocessing as cp\n", + "\n", + "plt.style.use(\n", + " \"/home/guerrini/matplotlib_config/paper.mplstyle\"\n", + ")\n", + "\n", + "plt.rc('text', usetex=True)\n", + "\n", + "sns.set_palette(\"husl\")\n", + "\n", + "g = plots.get_subplot_plotter(width_inch=30)\n", + "g.settings.axes_fontsize=60\n", + "g.settings.axes_labelsize=60\n", + "g.settings.alpha_filled_add = 0.7\n", + "g.settings.legend_fontsize = 60\n", + "\n", + "%matplotlib inline\n", + "\n", + "#SPECIFY DATA DIRECTORY AND DESIRED CHAINS TO ANALYSE\n", + "root_dir = \"/n09data/guerrini/output_chains/\"\n", + "root_external = f\"{root_dir}/ext_data/\"\n", + "blind = 'B'\n", + "\n", + "roots = [\n", + "f'SP_v1.4.6.3_{blind}_fiducial_config',\n", + "f'SP_v1.4.6.3_leak_corr_{blind}',\n", + "'Planck18',\n", + "'DES Y6',\n", + "'KiDS-Legacy_bandpowers',\n", + "'KiDS-Legacy_cosebis',\n", + "'KiDS-Legacy_xipm',\n", + "'HSC_Y3',\n", + "'HSC_Y3_cell',\n", + "f'SP_v1.4.6.3_{blind}_small_scales_config',\n", + "f'SP_v1.4.6.3_{blind}_flat_alpha_beta_config',\n", + "f'SP_v1.4.6.3_{blind}_no_xi_sys_config',\n", + "f'SP_v1.4.6.3_{blind}_no_leak_corr_config',\n", + "f'SP_v1.4.6.3_{blind}_flat_delta_z_config',\n", + "f'SP_v1.4.6.3_{blind}_no_delta_z_config',\n", + "f'SP_v1.4.6.3_{blind}_flat_ia_config',\n", + "f'SP_v1.4.6.3_{blind}_no_ia_config',\n", + "f'SP_v1.4.6.3_{blind}_no_m_bias_config',\n", + "f'SP_v1.4.6.3_{blind}_unmasked_covmat_config',\n", + "f'SP_v1.4.6.3_{blind}_halofit_config',\n", + "f'SP_v1.4.6.3_{blind}_no_baryons_config',\n", + "f'SP_v1.4.6.3_{blind}_nautilus_config',\n", + "f'SP_v1.4.6.3_{blind}_planck_config',\n", + "f'SP_v1.4.6.3_{blind}_planck_desi_config',\n", + "\n", + "]\n", + "\n", + "legend_labels = [\n", + " r\"UNIONS-3500 $\\xi_{\\pm}(\\theta)$ (This work)\",\n", + " \n", + " r\"UNIONS-3500 $C_\\ell$ (Guerrini et al. 2026)\",\n", + " \n", + " r\"$\\textit{Planck}$ 2018\",\n", + " r'DES Y6 $\\xi_{\\pm}$, NLA',\n", + " r\"KiDS-Legacy Bandpowers ($C_{\\rm E}$)\",\n", + " r\"KiDS-Legacy COSEBIs ($E_n$)\",\n", + " r\"KiDS-Legacy $\\xi_{\\pm}(\\theta)$\",\n", + " r\"HSC-Y3 $\\xi_{\\pm}(\\theta)$\",\n", + " r\"HSC-Y3 $C_\\ell$\",\n", + " \n", + " r\"$\\xi_+$ small scales, $\\theta$=[5,83] arcmin\",\n", + " r\"Flat $\\alpha_{\\rm{PSF}}$ and $\\beta_{\\rm{PSF}}$ priors\",\n", + " r\"No $\\xi^{\\rm sys}_{\\pm}$\",\n", + " r\"No leakage correction\",\n", + " r\"Flat $\\Delta z$ priors\",\n", + " r\"No $\\Delta z$\",\n", + " r\"Flat $A_{\\rm IA}$ prior\",\n", + " r\"No $A_{\\rm IA}$\",\n", + " r\"No $m$ bias\",\n", + " r\"Unmasked covmat\",\n", + " r\"$\\texttt{Halofit}$\",\n", + " r\"$\\texttt{HMCode}$ no baryons\",\n", + " r\"Nautilus sampler\",\n", + " r\"UNIONS-3500 + $\\textit{Planck}$\",\n", + " r\"UNIONS-3500 + $\\textit{Planck}$ + DESI BAO\",\n", + " ]\n", + "\n", + "categories = [\n", + " \"configuration\",\n", + " \"harmonic\", \n", + " \n", + " \"external\",\n", + " \"external\",\n", + " \"external\",\n", + " \"external\",\n", + " \"external\",\n", + " \"external\",\n", + " \n", + " \"configuration\",\n", + " \"configuration\",\n", + " \"configuration\",\n", + " \"configuration\",\n", + " \"configuration\",\n", + " \"configuration\",\n", + " \"configuration\",\n", + " \"configuration\",\n", + " \"configuration\",\n", + " \"configuration\",\n", + " \"configuration\",\n", + " \"configuration\",\n", + " \"configuration\",\n", + " \"configuration\",\n", + " \"configuration\",\n", + " \n", + "\n", + "]\n", + "colours = [\n", + " \"darkorange\",\n", + " \"royalblue\",\n", + "\n", + " \"violet\", \n", + " \"black\",\n", + " \"black\",\n", + " \"black\",\n", + " \"black\",\n", + " \"black\",\n", + " \"black\",\n", + " \"black\",\n", + " \n", + " \"forestgreen\",\n", + " \"forestgreen\",\n", + " \"forestgreen\",\n", + " \"forestgreen\",\n", + " \"forestgreen\",\n", + " \"forestgreen\",\n", + " \"forestgreen\",\n", + " \"forestgreen\",\n", + " \"forestgreen\",\n", + " \"forestgreen\",\n", + " \"forestgreen\",\n", + " \"forestgreen\",\n", + " \"forestgreen\",\n", + " \"forestgreen\",\n", + " \"forestgreen\",\n", + "]\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "694ae47f", + "metadata": {}, + "outputs": [], + "source": [ + "chains = []\n", + "for i, root in enumerate(roots):\n", + " category = categories[i]\n", + " if category != \"external\":\n", + " if category == 'configuration':\n", + " path_samples = os.path.join(\n", + " root_dir,\n", + " f\"{root}/samples_{root}.txt\"\n", + " )\n", + " path_getdist = os.path.join(\n", + " root_dir,\n", + " f\"{root}/getdist_{root}\"\n", + " )\n", + " elif category == 'harmonic':\n", + " path_samples = os.path.join(\n", + " root_dir,\n", + " f\"{root}/{root}/samples_{root}_cell.txt\"\n", + " )\n", + " path_getdist = os.path.join(\n", + " root_dir,\n", + " f\"{root}/{root}/getdist_{root}\"\n", + " )\n", + " elif category == \"external_compute_sample\":\n", + " path_samples = os.path.join(\n", + " root_dir,\n", + " f\"ext_data/{root}/samples_{root}.txt\"\n", + " )\n", + " path_getdist = os.path.join(\n", + " root_dir,\n", + " f\"ext_data/{root}/getdist_{root}\"\n", + " )\n", + " else:\n", + " raise ValueError(f\"The category, {category}, of {root} is not correct\")\n", + " if 'nautilus' not in root:\n", + " cp.load_samples_and_write_paramnames(path_samples, path_getdist+\".paramnames\")\n", + " cp.write_samples_getdist_format(path_samples, path_getdist+\".txt\")\n", + " chains.append(\n", + " cp.load_chain(path_getdist, smoothing_scale=0.5)\n", + " )\n", + " else:\n", + " path_getdist = os.path.join(\n", + " root_dir,\n", + " f\"ext_data/{root}/getdist_{root}\"\n", + " )\n", + " chains.append(\n", + " cp.load_chain(path_getdist)\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e57927c8", + "metadata": {}, + "outputs": [], + "source": [ + "name_list = ['OMEGA_M','ombh2','h0','n_s','SIGMA_8','S_8','s_8_input', 'logt_agn','a','m1','bias_1']\n", + "label_list = [r'\\Omega_{\\rm m}', r'\\omega_b h^2', r'h_0', r'n_s', r'\\sigma_8', r'S_8', r'S_8', r'\\log T_{\\rm AGN}', r'A_{\\rm IA}', r'm_1', r'\\Delta z_1']\n", + "\n", + "for i, chain in enumerate(chains):\n", + " print(legend_labels[i])\n", + " param_names = chain.getParamNames()\n", + " for name, label in zip(name_list, label_list):\n", + " try:\n", + " param_names.parWithName(name).label = label\n", + " except:\n", + " warnings.warn(f\"Parameter {name} not found in chain {roots[i]}.\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b0d924cb", + "metadata": {}, + "outputs": [], + "source": [ + "# Micro management of external chains\n", + "\n", + "# Account for the missing parameter conventions\n", + "\n", + "#OMEGA_M not in DES_Y3_cell\n", + "# idx = roots.index('DES_Y3_cell')\n", + "# cp.adjust_paramname_chain(chains[idx], 'omega_m', 'OMEGA_M', r'\\Omega_{\\rm m}')\n", + "# cp.derive_parameter_S8(chains[idx])\n", + "\n", + "idx = roots.index('KiDS-Legacy_xipm')\n", + "cp.derive_parameter_S8(chains[idx])\n", + "\n", + "idx = roots.index('KiDS-Legacy_bandpowers')\n", + "cp.derive_parameter_S8(chains[idx])\n", + "\n", + "idx = roots.index('KiDS-Legacy_cosebis')\n", + "cp.derive_parameter_S8(chains[idx])\n", + "\n", + "#OMEGA_M not in HSC_Y3_cell\n", + "idx = roots.index('HSC_Y3_cell')\n", + "cp.adjust_paramname_chain(chains[idx], 'omega_m', 'OMEGA_M', r'\\Omega_{\\rm m}')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d07b94e2", + "metadata": {}, + "outputs": [], + "source": [ + "param_values = np.array([\"# Expt\", \"Colour\", \"S8_Mean\", \"S8_low\", \"S8_high\", \"sigma_8_Mean\", \"sigma_8_low\", \"sigma_8_high\", \"Omega_m_Mean\", \"Omega_m_low\", \"Omega_m_high\"])\n", + "escaped = np.char.replace(legend_labels, '\\\\', '\\\\\\\\')\n", + "\n", + "for i, chain in enumerate(chains):\n", + " print(chain.root)\n", + " best_fit_params = cp.extract_best_fit_params(chain, best_fit_method='2Dkde')\n", + " margestats = chain.getMargeStats()\n", + "\n", + " s8_stats = margestats.parWithName('S_8')\n", + " sigma8_stats = margestats.parWithName('SIGMA_8')\n", + " omegam_stats = margestats.parWithName('OMEGA_M')\n", + "\n", + " param_values = np.vstack((\n", + " param_values,\n", + " [\n", + " escaped[i],\n", + " colours[i],\n", + " best_fit_params['S_8'],\n", + " best_fit_params['S_8'] - s8_stats.limits[0].lower,\n", + " s8_stats.limits[0].upper - best_fit_params['S_8'],\n", + " best_fit_params['SIGMA_8'],\n", + " best_fit_params['SIGMA_8'] - sigma8_stats.limits[0].lower,\n", + " sigma8_stats.limits[0].upper - best_fit_params['SIGMA_8'],\n", + " best_fit_params['OMEGA_M'],\n", + " best_fit_params['OMEGA_M'] - omegam_stats.limits[0].lower,\n", + " omegam_stats.limits[0].upper - best_fit_params['OMEGA_M'],\n", + " ]\n", + " ))\n", + "print(param_values)\n", + "np.savetxt(f\"{root_dir}/param_values.txt\", param_values, fmt=['%s' for i in range(11)], delimiter=';')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cc58ae5a", + "metadata": {}, + "outputs": [], + "source": [ + "# Load the value of the parameters\n", + "cosmo = np.loadtxt(f\"{root_dir}/param_values.txt\",\n", + " dtype={'names': ('Expt', 'colour', 's8_mean', 's8_low', 's8_high', 'sigma8_mean', 'sigma8_low', 'sigma8_high', 'omegam_mean', 'omegam_low', 'omegam_high'),\n", + " 'formats': ('U250', 'U20', 'U20', 'U20', 'U20', 'U20', 'U20', 'U20', 'U20', 'U20', 'U20')}, skiprows=1, delimiter=';')\n", + "expt = np.char.replace(cosmo['Expt'], '\\\\\\\\', '\\\\')\n", + "colours = cosmo['colour']\n", + "s8_mean = cosmo['s8_mean'].astype(np.float64)\n", + "s8_low = cosmo['s8_low'].astype(np.float64)\n", + "s8_high = cosmo['s8_high'].astype(np.float64)\n", + "sigma8_mean = cosmo['sigma8_mean'].astype(np.float64)\n", + "sigma8_low = cosmo['sigma8_low'].astype(np.float64)\n", + "sigma8_high = cosmo['sigma8_high'].astype(np.float64)\n", + "omegam_mean = cosmo['omegam_mean'].astype(np.float64)\n", + "omegam_low = cosmo['omegam_low'].astype(np.float64)\n", + "omegam_high = cosmo['omegam_high'].astype(np.float64)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d3da35ed", + "metadata": {}, + "outputs": [], + "source": [ + "from matplotlib.gridspec import GridSpec\n", + "\n", + "fig = plt.figure(figsize=(13, 8))\n", + "gs = GridSpec(1, 3, width_ratios=[1, 0.5, 0.5])\n", + "ax1 = fig.add_subplot(gs[0])\n", + "ax2 = fig.add_subplot(gs[1], sharey=ax1)\n", + "ax3 = fig.add_subplot(gs[2], sharey=ax1)\n", + "\n", + "axs = [ax1, ax2, ax3]\n", + "\n", + "params = [\n", + " (s8_mean, s8_low, s8_high, r\"$S_8$\"),\n", + " (sigma8_mean, sigma8_low, sigma8_high, r\"$\\sigma_8$\"),\n", + " (omegam_mean, omegam_low, omegam_high, r\"$\\Omega_{\\rm m}$\"),\n", + "]\n", + "reference = r\"UNIONS-3500 $\\xi_{\\pm}(\\theta)$ (This work)\"\n", + "\n", + "separation_after = [\n", + " r\"UNIONS-3500 $C_\\ell$ (Guerrini et al. 2026)\",\n", + " r\"HSC-Y3 $C_\\ell$\",\n", + " r\"$\\xi_+$ small scales, $\\theta$=[5,83] arcmin\",\n", + " r\"Unmasked covmat\", \n", + " r\"$\\texttt{HMCode}$ no baryons\",\n", + " r\"Nautilus sampler\",\n", + "]\n", + "list_section_index = [\n", + " r\"(ii)\",\n", + " r\"(iii)\",\n", + " r\"(iv)\",\n", + " r\"(v)\",\n", + " r\"(vi)\",\n", + " r\"(vii)\"\n", + "]\n", + "\n", + "preliminary_watermark = False\n", + "blind_axes = False\n", + "row_spacing = 0.2\n", + "\n", + "index_ref = np.where(expt == reference)[0][0]\n", + "\n", + "y = np.arange(len(expt))\n", + "for ax, param in zip(axs, params):\n", + " means, lows, highs, label = param\n", + " for i, mean, low, high, color in zip(y, means, lows, highs, colours):\n", + " ax.errorbar(mean, 0.05+i*row_spacing, xerr=np.array([low, high])[:, None], fmt='o', color=color, ecolor=color, elinewidth=2, capsize=3)\n", + " ax.set_xlabel(label, fontsize=14)\n", + " \n", + " ax.grid(False)\n", + " ax.tick_params(axis='y', left=False, labelleft=False)\n", + " if label == r\"$S_8$\":\n", + " ax.axvspan(s8_mean[index_ref] - s8_low[index_ref], s8_mean[index_ref] + s8_high[index_ref], color=colours[index_ref], alpha=0.2)\n", + " ax.set_xlim(0.6, 1.35)\n", + " if blind_axes:\n", + " ref_tick = np.mean(s8_mean[:4])\n", + " ax.set_xticks(\n", + " [ref_tick + i*0.1 for i in range(-5, 5)], labels=[]\n", + " )\n", + " elif label == r\"$\\sigma_8$\":\n", + " ax.axvspan(sigma8_mean[index_ref] - sigma8_low[index_ref], sigma8_mean[index_ref] + sigma8_high[index_ref], color=colours[index_ref], alpha=0.2)\n", + " ax.set_xlim(0.5, 1.35)\n", + " if blind_axes:\n", + " ref_tick = np.mean(sigma8_mean[:4])\n", + " ax.set_xticks(\n", + " [ref_tick + i*0.2 for i in range(-2, 2)], labels=[]\n", + " )\n", + " elif label == r\"$\\Omega_{\\rm m}$\":\n", + " ax.axvspan(omegam_mean[index_ref] - omegam_low[index_ref], omegam_mean[index_ref] + omegam_high[index_ref], color=colours[index_ref], alpha=0.2)\n", + " ax.set_xlim(0.1, 0.5)\n", + " if blind_axes:\n", + " ref_tick = np.mean(omegam_mean[:4])\n", + " ax.set_xticks(\n", + " [ref_tick + i*0.1 for i in range(-2, 3)], labels=[]\n", + " )\n", + "\n", + "\n", + "axs[0].set_yticks(0.01+y*row_spacing)\n", + "axs[0].set_yticklabels([])\n", + "for label, color in zip(expt, colours):\n", + " if 'This work' in label:\n", + " label_bold = r\"$\\bf{UNIONS}$-$\\bf{3500}$ $\\xi_{\\pm}(\\theta)$ $\\bf{(This\\ work)}$\"\n", + " axs[0].text(-0.6, 0.05 + row_spacing * np.where(expt == label)[0][0], label_bold, fontsize=12, ha='left', va='center', color=color)\n", + " else: \n", + " axs[0].text(-0.6, 0.05 + row_spacing * np.where(expt == label)[0][0], label, fontsize=12, ha='left', va='center', color=color)\n", + " if label != reference:\n", + " index = np.where(expt == label)[0][0]\n", + " s8_tension = cp.get_sigma_tension(\n", + " s8_mean[index], s8_low[index], s8_high[index],\n", + " s8_mean[index_ref], s8_low[index_ref], s8_high[index_ref]\n", + " )\n", + " sign_str = \"+\" if s8_tension > 0 else \"-\"\n", + " axs[0].text(1.32, 0.05 + row_spacing * index, rf\"${sign_str}{np.abs(s8_tension):.2f}\" + r\"\\, \\sigma$\", fontsize=10, ha='right', va='center', color=color)\n", + "# Add separation lines\n", + "for i, sep in enumerate(separation_after):\n", + " print(sep)\n", + " index_sep = np.where(expt == sep)[0][0]\n", + " for ax in axs:\n", + " ax2.axhline(row_spacing * (index_sep + 1) - 0.07, color='black', linestyle='dotted', linewidth=1)\n", + " ax3.axhline(row_spacing * (index_sep + 1) - 0.07, color='black', linestyle='dotted', linewidth=1)\n", + " ax1.axhline(row_spacing * (index_sep + 1) - 0.07, xmin=-1.8,color='black', linestyle='dotted', linewidth=1, clip_on=False)\n", + " axs[0].text(-0.61, row_spacing * (index_sep + 1) + 0.05, \n", + " list_section_index[i], fontsize=12, fontweight='bold', va='center', ha='right')\n", + "\n", + "\n", + "# --- Add section label (i)) ---\n", + "axs[0].text(-0.61, 0.05, \n", + " r\"(i)\", fontsize=12, fontweight='bold', va='center', ha='right')\n", + "\n", + "if preliminary_watermark:\n", + " plt.figtext(0.5, 0.5, 'PRELIMINARY',\n", + " fontsize=50, color='gray',\n", + " ha='center', va='center',\n", + " alpha=0.3, rotation=330)\n", + "\n", + "plt.gca().invert_yaxis()\n", + "\n", + "plt.tight_layout()\n", + "\n", + "# plt.savefig(\"./plots/whisker_plot.png\", dpi=300)\n", + "# #Save pdf\n", + "plt.savefig(\"../Plots/S8_whisker_plot.pdf\", bbox_inches='tight')\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "841b6d6b", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "my_env", + "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.10.13" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/cosmo_inference/notebooks/2D_cosmic_shear_configuration_plots/best_fit_xipm.ipynb b/cosmo_inference/notebooks/2D_cosmic_shear_configuration_plots/best_fit_xipm.ipynb new file mode 100644 index 00000000..a8377921 --- /dev/null +++ b/cosmo_inference/notebooks/2D_cosmic_shear_configuration_plots/best_fit_xipm.ipynb @@ -0,0 +1,477 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "88f4c8fd", + "metadata": {}, + "source": [ + "# Best-fit $\\xi_\\pm$\n", + "\n", + "This notebook plots the best-fit 2PCFs for the fiducial and other cases" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7540c690", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import configparser\n", + "import subprocess\n", + "import sys\n", + "import warnings\n", + "\n", + "import sys\n", + "sys.path.append(\"/home/guerrini/sp_validation/cosmo_inference/scripts\")\n", + "\n", + "import chain_postprocessing as cp\n", + "\n", + "from getdist import plots, loadMCSamples\n", + "from astropy.io import fits\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "from scipy.interpolate import interp1d\n", + "import scipy.stats as stats\n", + "from IPython.display import Markdown, display\n", + "import healpy as hp\n", + "import matplotlib.scale as mscale\n", + "import matplotlib.ticker as ticker\n", + "import matplotlib.transforms as mtransforms\n", + "import seaborn as sns\n", + "\n", + "plt.style.use(\n", + " \"/home/guerrini/matplotlib_config/paper.mplstyle\"\n", + ")\n", + "\n", + "from sp_validation.rho_tau import SquareRootScale\n", + "mscale.register_scale(SquareRootScale)\n", + "\n", + "plt.rcParams[\"text.usetex\"] = True\n", + "\n", + "sns.set_palette(\"husl\")\n", + "\n", + "g = plots.get_subplot_plotter(width_inch=30)\n", + "g.settings.axes_fontsize=40\n", + "g.settings.axes_labelsize=40\n", + "g.settings.alpha_filled_add = 0.7\n", + "g.settings.legend_fontsize = 50\n", + "\n", + "# Directory where the chains are located\n", + "root_dir = \"/n09data/guerrini/output_chains\"\n", + "\n", + "# THE BLIND TO USE FOR THE PLOTS\n", + "blind = \"B\"\n", + "catalog_version = \"SP_v1.4.6.3\"\n", + "fiducial_root_cell = f\"SP_v1.4.6.3_leak_corr_{blind}\"\n", + "label_fiducial_cell = r\"UNIONS $C_{\\ell}$\"\n", + "fiducial_root_xi_data = f\"SP_v1.4.6.3_leak_corr_{blind}_masked\"\n", + "fiducial_root_xi_chains = f\"SP_v1.4.6.3_{blind}_fiducial_config\"\n", + "label_fiducial_xi = r\"UNIONS $\\xi_{\\pm}$\"\n", + "\n", + "# Path to the ini files used\n", + "path_ini_files = '/home/guerrini/sp_validation/cosmo_inference/cosmosis_config'\n", + "path_datavectors = '/home/guerrini/sp_validation/cosmo_inference/data/'\n", + "path_output_chains = \"/n09data/guerrini/output_chains/\"\n", + "\n", + "\n", + "data_cell = fits.open(\n", + " os.path.join(\n", + " path_datavectors,\n", + " f\"{fiducial_root_cell}/cosmosis_{fiducial_root_cell}.fits\"\n", + " )\n", + ")\n", + "\n", + "data_xi = fits.open(\n", + " os.path.join(\n", + " path_datavectors,\n", + " f\"SP_v1.4.6.3_config/SP_v1.4.6.3_{blind}/cosmosis_{fiducial_root_xi_data}.fits\"\n", + " )\n", + ")\n", + "\n", + "%matplotlib inline" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "46600388", + "metadata": {}, + "outputs": [], + "source": [ + "\n", + "# Perform the computation for the fiducial of Cell\n", + "path_samples_fiducial_cell = os.path.join(\n", + " path_output_chains,\n", + " fiducial_root_cell,\n", + " fiducial_root_cell,\n", + " f\"samples_{fiducial_root_cell}_cell.txt\"\n", + ")\n", + "path_gd_fiducial_cell = os.path.join(\n", + " path_output_chains,\n", + " fiducial_root_cell,\n", + " fiducial_root_cell,\n", + " f\"getdist_{fiducial_root_cell}_cell\"\n", + ")\n", + "cp.load_samples_and_write_paramnames(path_samples_fiducial_cell, path_gd_fiducial_cell+\".paramnames\")\n", + "cp.write_samples_getdist_format(path_samples_fiducial_cell, path_gd_fiducial_cell+\".txt\", chain_type='polychord')\n", + "\n", + "chain_fiducial_cell = cp.load_chain(path_gd_fiducial_cell, smoothing_scale=0.5)\n", + "\n", + "best_fit_params_fiducial_cell = cp.extract_best_fit_params(chain_fiducial_cell, best_fit_method='2Dkde')\n", + "\n", + "cp.compute_best_fit(\n", + " path_ini_files,\n", + " best_fit_params_fiducial_cell,\n", + " fiducial_root_cell,\n", + " is_harmonic=True,\n", + " blind=blind\n", + ")\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f512a9fc", + "metadata": {}, + "outputs": [], + "source": [ + "\n", + "# Perform the computation for the fiducial of xi\n", + "path_samples_fiducial_xi = os.path.join(\n", + " path_output_chains,\n", + " fiducial_root_xi_chains,\n", + " f\"samples_{fiducial_root_xi_chains}.txt\"\n", + ")\n", + "\n", + "path_gd_fiducial_xi = os.path.join(\n", + " path_output_chains,\n", + " fiducial_root_xi_chains,\n", + " f\"getdist_{fiducial_root_xi_chains}\"\n", + ")\n", + "cp.load_samples_and_write_paramnames(path_samples_fiducial_xi, path_gd_fiducial_xi+\".paramnames\")\n", + "cp.write_samples_getdist_format(path_samples_fiducial_xi, path_gd_fiducial_xi+\".txt\", chain_type='polychord')\n", + "\n", + "chain_fiducial_xi = cp.load_chain(path_gd_fiducial_xi, smoothing_scale=0.5)\n", + "\n", + "best_fit_params_fiducial_xi = cp.extract_best_fit_params(chain_fiducial_xi, best_fit_method='2Dkde')\n", + "\n", + "ini_file_root = os.path.join(\n", + " path_ini_files,\n", + " f'config_space_v1.4.6.3_fiducial/pipeline/blind_{blind}/fiducial.ini'\n", + ")\n", + "cp.compute_best_fit(\n", + " path_ini_files,\n", + " best_fit_params_fiducial_xi,\n", + " fiducial_root_xi_chains,\n", + " is_harmonic=False,\n", + " blind=blind,\n", + " ini_file_root=ini_file_root\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ec3b8452", + "metadata": {}, + "outputs": [], + "source": [ + "# Make the plot for the best-fit datavector for Cell EE\n", + "root_to_plot = [\n", + " fiducial_root_xi_chains,\n", + " fiducial_root_cell,\n", + "]\n", + "\n", + "labels = [\n", + " r\"UNIONS $\\xi_\\pm(\\theta)$\",\n", + " r\"UNIONS $C_\\ell$\",\n", + "]\n", + "\n", + "line_args = [\n", + " {'color': 'royalblue', 'linestyle': '-'},\n", + " {'color': 'orange', 'linestyle': '-'}\n", + "]\n", + "\n", + "properties = {}\n", + "\n", + "properties = cp.update_properties_w_roots(properties, fiducial_root_cell, path_ini_files, with_configuration=False)\n", + "properties = cp.update_properties_w_roots(properties, fiducial_root_xi_chains, path_ini_files, with_configuration=True, path_to_this_ini=ini_file_root)\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3795f5a0", + "metadata": {}, + "outputs": [], + "source": [ + "root_to_plot = [\n", + " fiducial_root_cell,\n", + " fiducial_root_xi_chains\n", + "]\n", + "labels = [\n", + " r\"Best fit $C_\\ell$\",\n", + " r\"Best fit $\\xi_\\pm(\\theta)$\"\n", + "]\n", + "path_best_fit_xi_theta = os.path.join(\n", + " path_output_chains,\n", + " fiducial_root_xi_chains,\n", + " \"best_fit/shear_xi_plus/\"\n", + " f\"theta.txt\"\n", + ")\n", + "\n", + "theta_rad = np.loadtxt(path_best_fit_xi_theta)\n", + "theta_min = 1\n", + "theta_max = 250\n", + "\n", + "cp.compute_best_fit_xi_from_cell(path_output_chains, fiducial_root_cell, best_fit_params_fiducial_cell, theta_rad)\n", + "\n", + "data = fits.open(os.path.join(path_datavectors,f\"SP_v1.4.6.3_config/SP_v1.4.6.3_{blind}/cosmosis_{fiducial_root_xi_data}.fits\"))\n", + "bbox_to_anchor_xip = (0.685, 0.09)\n", + "bbox_to_anchor_xim = (0.3, 0.65)\n", + "xi_p_data = data['XI_PLUS'].data\n", + "xi_m_data = data['XI_MINUS'].data\n", + "cov_mat = data['COVMAT'].data\n", + "\n", + "# Plot hyperparameter\n", + "loc_legend = \"lower center\"\n", + "\n", + "fig, [ax,ax2] = plt.subplots(1, 2, figsize=(20, 8))\n", + "\n", + "theta, xi_p, xi_m = xi_p_data['ANG'], xi_p_data['VALUE'], xi_m_data['VALUE']\n", + "ax.errorbar(theta, theta*xi_p, yerr=theta*np.sqrt(np.diag(cov_mat[:len(theta),:len(theta)])), fmt='o', label=r\"UNIONS $\\xi_+$ data\", color='black', capsize=2)\n", + "ax2.errorbar(theta, theta*xi_m, yerr=theta*np.sqrt(np.diag(cov_mat[len(theta):2*len(theta),len(theta):2*len(theta)])), fmt='o', label=r\"UNIONS $\\xi_-$ data\", color='black', capsize=2)\n", + "\n", + "for idx, (label, root) in enumerate(zip(labels, root_to_plot)):\n", + " #Read the results\n", + " theta = (np.loadtxt(path_output_chains + '{}/best_fit/shear_xi_plus/theta.txt'.format(root))) * 180/np.pi * 60\n", + " xi_plus = np.loadtxt(path_output_chains + '{}/best_fit/shear_xi_plus/bin_1_1.txt'.format(root))\n", + " xi_minus = np.loadtxt(path_output_chains + '{}/best_fit/shear_xi_minus/bin_1_1.txt'.format(root))\n", + " if '$C_\\ell$' not in label:\n", + " xi_sys_plus = np.loadtxt(path_output_chains + '{}/best_fit/xi_sys/shear_xi_plus.txt'.format(root))\n", + " xi_sys_minus = np.loadtxt(path_output_chains + '{}/best_fit/xi_sys/shear_xi_minus.txt'.format(root))\n", + " theta_xi_sys = np.loadtxt(path_output_chains + '{}/best_fit/xi_sys/theta.txt'.format(root)) * 180/np.pi * 60\n", + " \n", + " xi_sys_plus = np.interp(theta, theta_xi_sys, xi_sys_plus)\n", + " xi_sys_minus = np.interp(theta, theta_xi_sys, xi_sys_minus)\n", + " xi_plus += xi_sys_plus\n", + " xi_minus += xi_sys_minus\n", + "\n", + " mask = (theta > theta_min) & (theta < theta_max)\n", + " theta = theta[mask]\n", + " ax.plot(theta, theta*xi_plus[mask], label=r\"Best fit $\\xi_+(\\theta)$\", **line_args[idx], lw=2.5)\n", + " ax.plot(theta, theta*xi_sys_plus[mask], label=r\"Best fit $\\xi^{\\rm sys}_{+}(\\theta)$\", c='r')\n", + " ax2.plot(theta, theta*xi_minus[mask], label=r\"Best fit $\\xi_-(\\theta)$\", **line_args[idx], lw=2.5)\n", + " ax2.plot(theta, theta*xi_sys_minus[mask], label=r\"Best fit $\\xi^{\\rm sys}_{-}(\\theta)$\", c='r')\n", + " \n", + " else:\n", + " mask = (theta > theta_min) & (theta < theta_max)\n", + " theta = theta[mask]\n", + " ax.plot(theta, theta*xi_plus[mask], label=label, **line_args[idx], lw=2.5)\n", + " ax2.plot(theta, theta*xi_minus[mask], label=label, **line_args[idx], lw=2.5)\n", + "# XI PLUS PLOT SETTINGS\n", + "\n", + "# Plot the scale cuts for different k_max\n", + "ax.axvline(x=5, color='gray', linestyle='--', alpha=0.7)\n", + "ax.axhline(y=0, color='black', linestyle='--', alpha=0.7)\n", + "\n", + "ymin = ax.get_ylim()[0]\n", + "ymax = ax.get_ylim()[1]\n", + "# Shadowing cut scaled\n", + "ax.fill_betweenx(y=[ymin, ymax], x1=0, x2=12, color='gray', alpha=0.2, label=r'$B$-mode informed scale cut')\n", + "ax.fill_betweenx(y=[ymin, ymax], x1=83, x2=250, color='gray', alpha=0.2)\n", + "\n", + "ax.set_ylim(ymin, ymax)\n", + "\n", + "# Add labels directly under the tick\n", + "ax.text(4.5, 0.47e-4,\n", + " r\"$k_\\mathrm{max} = 1 h$ Mpc$^{-1}$\",\n", + " ha='center', va='top', fontsize=20, rotation=90)\n", + "\n", + "ax.set_ylabel(r'$\\theta \\xi_\\pm$', fontsize=26)\n", + "ax.set_xlabel(r'$\\theta$ (arcmin)', fontsize=26)\n", + "ax.set_xlim([theta.min()-0.1, theta.max()+20])\n", + "ax.set_title(r'$\\xi_+(\\theta)$', fontsize=26)\n", + "ax.set_xscale('log')\n", + "ax.set_xticks(np.array([1, 10, 100]))\n", + "ax.tick_params(axis=\"x\", which=\"minor\", length=2, width=0.8)\n", + "ax.tick_params(axis='both', which='major', labelsize=24)\n", + "ax.tick_params(axis='both', which='minor', labelsize=20)\n", + "ax.yaxis.get_offset_text().set_fontsize(24)\n", + "ax.ticklabel_format(axis='y', style='sci', scilimits=(0,0))\n", + "ax.legend(loc=loc_legend, bbox_to_anchor=bbox_to_anchor_xip, fontsize=20)\n", + "\n", + "# XI_MINUS PLOT SETTINGS\n", + "\n", + "# Plot the scale cuts for different k_max\n", + "ax2.axvline(x=50, color='gray', linestyle='--', alpha=0.7)\n", + "ax2.axhline(y=0, color='black', linestyle='--', alpha=0.7)\n", + "\n", + "ymin = ax2.get_ylim()[0]\n", + "ymax = ax2.get_ylim()[1]\n", + "# Shadowing cut scaled\n", + "ax2.fill_betweenx(y=[ymin, ymax], x1=0, x2=12, color='gray', alpha=0.2, label=r'$B$-mode informed scale cut')\n", + "ax2.fill_betweenx(y=[ymin, ymax], x1=83, x2=250, color='gray', alpha=0.2)\n", + "\n", + "ax2.set_ylim(ymin, ymax)\n", + "\n", + "# Add labels directly under the tick\n", + "ax2.text(45, 1.15e-4,\n", + " r\"$k_\\mathrm{max} = 1 h$ Mpc$^{-1}$\",\n", + " ha='center', va='top', fontsize=20, rotation=90)\n", + "\n", + "# ax2.set_ylabel(r'$\\theta \\xi_-$', fontsize=16)\n", + "ax2.set_xlabel(r'$\\theta$ (arcmin)', fontsize=26)\n", + "ax2.set_xlim([theta.min()-0.1, theta.max()+20])\n", + "ax2.set_xscale('log')\n", + "ax2.set_title(r'$\\xi_-(\\theta)$', fontsize=26)\n", + "ax2.set_xticks(np.array([1, 10, 100]))\n", + "ax2.tick_params(axis=\"x\", which=\"minor\", length=2, width=0.8)\n", + "ax2.tick_params(axis='both', which='major', labelsize=24)\n", + "ax2.tick_params(axis='both', which='minor', labelsize=20)\n", + "ax2.yaxis.get_offset_text().set_fontsize(24)\n", + "ax2.ticklabel_format(axis='y', style='sci', scilimits=(0,0))\n", + "ax2.legend(loc=loc_legend, bbox_to_anchor=bbox_to_anchor_xim, fontsize=20)\n", + "\n", + "plt.savefig(\"/n23data1/n06data/lgoh/scratch/UNIONS/cosmo_inference/notebooks/2D_cosmic_shear_configuration_plots/best_fit_xipm_SP_v1.4.6.3_B.pdf\", bbox_inches='tight')\n", + "\n", + "plt.show()\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "98a1fd8f", + "metadata": {}, + "outputs": [], + "source": [ + "root_to_plot = [\n", + " fiducial_root_xi_chains\n", + "]\n", + "labels = [\n", + " r\"Best fit $\\tau_{0,2}(\\theta)$\"\n", + "]\n", + "\n", + "bbox_to_anchor_xip = (0.285, 0.7)\n", + "bbox_to_anchor_xim = (0.3, 0.65)\n", + "tau0_data = data['TAU_0_PLUS'].data\n", + "tau2_data = data['TAU_2_PLUS'].data\n", + "cov_mat = data['COVMAT'].data\n", + "\n", + "# Plot hyperparameter\n", + "\n", + "fig, [ax,ax2] = plt.subplots(1, 2, figsize=(20, 8))\n", + "\n", + "theta, tau0, tau2 = tau0_data['ANG'], tau0_data['VALUE'], tau2_data['VALUE']\n", + "ax.errorbar(theta, theta*tau0, yerr=theta*np.sqrt(np.diag(cov_mat[2*len(theta):3*len(theta),2*len(theta):3*len(theta)])), fmt='o', label=r\"UNIONS $\\tau_{0,+}$\", color='black', capsize=2)\n", + "ax2.errorbar(theta, theta*tau2, yerr=theta*np.sqrt(np.diag(cov_mat[3*len(theta):4*len(theta),3*len(theta):4*len(theta)])), fmt='o', label=r\"UNIONS $\\tau_{2,+}$\", color='black', capsize=2)\n", + "\n", + "for idx, (label, root) in enumerate(zip(labels, root_to_plot)):\n", + " #Read the results\n", + " theta = (np.loadtxt(path_output_chains + '{}/best_fit/tau_0_plus/theta.txt'.format(root))) * 180/np.pi * 60\n", + " tau0_plus = np.loadtxt(path_output_chains + '{}/best_fit/tau_0_plus/bin_1_1.txt'.format(root))\n", + " tau2_plus = np.loadtxt(path_output_chains + '{}/best_fit/tau_2_plus/bin_1_1.txt'.format(root))\n", + " \n", + " mask = (theta > theta_min) & (theta < theta_max)\n", + " theta = theta[mask]\n", + " ax.plot(theta, theta*tau0_plus[mask], label=r\"Best fit $\\tau_{0,+}(\\theta)$\", c='orange', lw=2.5)\n", + " ax2.plot(theta, theta*tau2_plus[mask], label=r\"Best fit $\\tau_{2,+}(\\theta)$\", c='orange', lw=2.5)\n", + "\n", + "# XI PLUS PLOT SETTINGS\n", + "\n", + "# Plot the scale cuts for different k_max\n", + "ax.axhline(y=0, color='black', linestyle='--', alpha=0.7)\n", + "\n", + "ymin = ax.get_ylim()[0]\n", + "ymax = ax.get_ylim()[1]\n", + "# Shadowing cut scaled\n", + "ax.fill_betweenx(y=[ymin, ymax], x1=0, x2=12, color='gray', alpha=0.2, label=r'$B$-mode informed scale cut')\n", + "ax.fill_betweenx(y=[ymin, ymax], x1=83, x2=250, color='gray', alpha=0.2)\n", + "\n", + "ax.set_ylim(ymin, ymax)\n", + "\n", + "ax.set_ylabel(r'$\\theta\\tau_{0,2}$', fontsize=26)\n", + "ax.set_xlabel(r'$\\theta$ (arcmin)', fontsize=26)\n", + "ax.set_xlim([theta.min()-0.1, theta.max()+20])\n", + "ax.set_title(r'$\\tau_{0,+}(\\theta)$', fontsize=26)\n", + "ax.set_xscale('log')\n", + "ax.set_xticks(np.array([1, 10, 100]))\n", + "ax.tick_params(axis=\"x\", which=\"minor\", length=2, width=0.8)\n", + "ax.tick_params(axis='both', which='major', labelsize=24)\n", + "ax.tick_params(axis='both', which='minor', labelsize=20)\n", + "ax.yaxis.get_offset_text().set_fontsize(24)\n", + "ax.ticklabel_format(axis='y', style='sci', scilimits=(0,0))\n", + "ax.legend(loc=loc_legend, bbox_to_anchor=bbox_to_anchor_xip, fontsize=20)\n", + "\n", + "# XI_MINUS PLOT SETTINGS\n", + "\n", + "# Plot the scale cuts for different k_max\n", + "ax2.axhline(y=0, color='black', linestyle='--', alpha=0.7)\n", + "\n", + "ymin = ax2.get_ylim()[0]\n", + "ymax = ax2.get_ylim()[1]\n", + "# Shadowing cut scaled\n", + "ax2.fill_betweenx(y=[ymin, ymax], x1=0, x2=12, color='gray', alpha=0.2, label=r'$B$-mode informed scale cut')\n", + "ax2.fill_betweenx(y=[ymin, ymax], x1=83, x2=250, color='gray', alpha=0.2)\n", + "\n", + "ax2.set_ylim(ymin, ymax)\n", + "\n", + "# ax2.set_ylabel(r'$\\theta \\xi_-$', fontsize=16)\n", + "ax2.set_xlabel(r'$\\theta$ (arcmin)', fontsize=26)\n", + "ax2.set_xlim([theta.min()-0.1, theta.max()+20])\n", + "ax2.set_xscale('log')\n", + "ax2.set_title(r'$\\tau_{2,+}(\\theta)$', fontsize=26)\n", + "ax2.set_xticks(np.array([1, 10, 100]))\n", + "ax2.tick_params(axis=\"x\", which=\"minor\", length=2, width=0.8)\n", + "ax2.tick_params(axis='both', which='major', labelsize=24)\n", + "ax2.tick_params(axis='both', which='minor', labelsize=20)\n", + "ax2.yaxis.get_offset_text().set_fontsize(24)\n", + "ax2.ticklabel_format(axis='y', style='sci', scilimits=(0,0))\n", + "ax2.legend(loc=loc_legend, bbox_to_anchor=bbox_to_anchor_xim, fontsize=20)\n", + "\n", + "plt.savefig(\"/n23data1/n06data/lgoh/scratch/UNIONS/cosmo_inference/notebooks/Plots/best_fit_tau_02_SP_v1.4.6.3_B.pdf\", bbox_inches='tight')\n", + "\n", + "plt.show()\n", + " \n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "33f556c3", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "jupytext": { + "cell_metadata_filter": "-all", + "main_language": "python", + "notebook_metadata_filter": "-all" + }, + "kernelspec": { + "display_name": "my_env", + "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.10.13" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/cosmo_inference/notebooks/2D_cosmic_shear_configuration_plots/contours.ipynb b/cosmo_inference/notebooks/2D_cosmic_shear_configuration_plots/contours.ipynb new file mode 100644 index 00000000..a2db686c --- /dev/null +++ b/cosmo_inference/notebooks/2D_cosmic_shear_configuration_plots/contours.ipynb @@ -0,0 +1,763 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "e2675175", + "metadata": {}, + "source": [ + "# 2D contour plots\n", + "\n", + "This notebook produces the plots for all the 2D contours in the results section." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5e65319a-63f3-47d7-90cd-7b7db06174e9", + "metadata": {}, + "outputs": [], + "source": [ + "from getdist import plots, loadMCSamples\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "import os.path\n", + "import seaborn as sns\n", + "from astropy.io import fits\n", + "\n", + "plt.style.use(\n", + " \"/home/guerrini/matplotlib_config/paper.mplstyle\"\n", + ")\n", + "\n", + "plt.rcParams[\"text.usetex\"] = True\n", + "\n", + "sns.set_palette(\"husl\")\n", + "g = plots.get_subplot_plotter(width_inch=30)\n", + "g.settings.axes_fontsize=70\n", + "g.settings.axes_labelsize=80\n", + "g.settings.alpha_filled_add = 0.7\n", + "g.settings.legend_fontsize =70\n", + "\n", + "\n", + "#SPECIFY DATA DIRECTORY AND DESIRED CHAINS TO ANALYSE\n", + "\n", + "root_dir = '/n09data/guerrini/output_chains/'\n", + "path_datavectors = '/home/guerrini/sp_validation/cosmo_inference/data/'\n", + "path_output_chains = \"/n09data/guerrini/output_chains/\"\n", + "\n", + "data = fits.open(os.path.join(path_datavectors,f\"SP_v1.4.6.3_config/SP_v1.4.6.3_B/cosmosis_SP_v1.4.6.3_leak_corr_B_masked.fits\"))\n", + "\n", + "roots_fid = {\n", + "'SP_v1.4.6.3_leak_corr_B': r\"UNIONS-3500 $C_\\ell$\",\n", + "'SP_v1.4.6.3_B_fiducial_config': r\"UNIONS-3500 $\\xi_\\pm$ (This work) \",\n", + "\n", + "'KiDS-Legacy_xipm': r\"KiDS-Legacy $\\xi_\\pm$\",\n", + "'HSC_Y3': r\"HSC-Y3 $\\xi_\\pm$\",\n", + "'Planck18': r\"$\\textit{Planck}$ 2018\",\n", + "}\n", + "\n", + "roots_full = {\n", + "'SP_v1.4.6.3_B_fiducial_config': r\"UNIONS-3500 $\\xi_\\pm$ (This work) \",\n", + "}\n", + "\n", + "roots_ia = {\n", + "'SP_v1.4.6.3_B_fiducial_config': r\"Gaussian $A_{\\rm{IA}}$ prior\",\n", + "'SP_v1.4.6.3_B_flat_ia_config': r\"Flat $A_{\\rm{IA}}$ prior\",\n", + "'SP_v1.4.6.3_B_no_ia_config': r\"No IA\",\n", + "}\n", + "\n", + "roots_ext = {\n", + "'SP_v1.4.6.3_B_fiducial_config': r\"UNIONS-3500 $\\xi_\\pm$\",\n", + "'SP_v1.4.6.3_B_planck_config': r\"UNIONS-3500 $\\xi_\\pm$ + CMB\",\n", + "'SP_v1.4.6.3_B_planck_desi_config': r\"UNIONS-3500 $\\xi_\\pm$ + CMB + BAO\",\n", + "'Planck18': r\"$\\textit{Planck}$ 2018\",\n", + "}\n", + "\n", + "roots_dz = {\n", + "'SP_v1.4.6.3_B_fiducial_config': r\"Gaussian $\\Delta z$ prior\",\n", + "'SP_v1.4.6.3_B_flat_delta_z_config': r\"Flat $\\Delta z$ prior\",\n", + "'SP_v1.4.6.3_B_no_delta_z_config': r\"No $\\Delta z$ modelling\",\n", + "}\n", + "\n", + "roots_psf = {\n", + "'SP_v1.4.6.3_B_flat_alpha_beta_config': r\"Flat $\\alpha$ and $\\beta$ priors\",\n", + "'SP_v1.4.6.3_B_fiducial_config': r\"Gaussian $\\alpha$ and $\\beta$ priors\",\n", + "'SP_v1.4.6.3_B_no_xi_sys_config': r\"No $\\xi^{\\rm sys}$ included\",\n", + "'SP_v1.4.6.3_B_no_leak_corr_config': r\"No object-wise leakage correction\",\n", + "}\n", + "\n", + "roots_scale = {\n", + "'SP_v1.4.6.3_B_fiducial_config': r\"$\\xi_+$: $\\theta=[12,83]$\",\n", + "'SP_v1.4.6.3_B_small_scales_config': r\"$\\xi_+$: $\\theta=[5,83]$\"\n", + "}\n", + "\n", + "roots_nonlin = {\n", + "'SP_v1.4.6.3_B_fiducial_config': r\"Fiducial (\\texttt{HMCode2020}, $\\log(T_{\\rm AGN})$)\",\n", + "'SP_v1.4.6.3_B_no_baryons_config': r\"\\texttt{HMCode2020} no baryons\",\n", + "'SP_v1.4.6.3_B_halofit_config': r\"\\texttt{Halofit}\",\n", + "}\n", + "roots = roots_ext\n", + " " + ] + }, + { + "cell_type": "markdown", + "id": "70549903-a160-4a3e-a202-bd5a9d6b45eb", + "metadata": {}, + "source": [ + "## Retrieve the chains" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4795888c-ce6f-4fe2-bbd4-fe17b5e57f02", + "metadata": {}, + "outputs": [], + "source": [ + "#READ CHAIN\n", + "\n", + "chains=[]\n", + "\n", + "for i, root in enumerate(list(roots.keys())):\n", + " \n", + " burnin = 0\n", + " if 'SP' not in root:\n", + " chain = g.samples_for_root(root_dir + 'ext_data/{}/getdist_{}'.format(root, root),\n", + " cache=False,\n", + " settings={'ignore_rows': burnin,\n", + " # 'smooth_scale_2D':0.2,\n", + " # 'smooth_scale_1D':0.2\n", + " })\n", + " p = chain.getParams()\n", + " if hasattr(p, 'S_8')==False:\n", + " omega_m = chain.getParams().OMEGA_M\n", + " sigma_8 = chain.getParams().SIGMA_8\n", + "\n", + " s_8 = sigma_8 * (omega_m / 0.3) ** 0.5\n", + "\n", + " chain.addDerived(s_8, name='S_8', label=r'S_8')\n", + "\n", + " p = chain.paramNames.parWithName('S_8')\n", + " \n", + " elif 'config' in root:\n", + " if os.path.isfile(root_dir + '{}/getdist_{}.txt'.format(root, root))==False:\n", + " \n", + " samples = np.loadtxt(root_dir + '{}/samples_{}.txt'.format(root, root))\n", + " \n", + " if 'nautilus' in root:\n", + " weights = np.exp(samples[:, -3])\n", + " neglogL = samples[:, -2] - samples[:, -1]\n", + "\n", + " samples = np.column_stack((weights, neglogL, samples[:, 0:-3]))\n", + " elif 'mh' in root:\n", + " samples = np.column_stack((np.ones_like(samples[:,-1]),np.log(samples[:,-1])-np.log(samples[:,-2]), samples[:,0:-2]))\n", + " burnin=0.3\n", + " else:\n", + " print(\"here\")\n", + " samples = np.column_stack((samples[:,-1],samples[:,-3],samples[:,0:-4]))\n", + " \n", + " np.savetxt(root_dir + '{}/getdist_{}.txt'.format(root, root), samples)\n", + " \n", + " chain = g.samples_for_root(root_dir + '{}/getdist_{}'.format(root, root),\n", + " cache=False,\n", + " settings={'ignore_rows': burnin,\n", + " # 'smooth_scale_2D':0.2,\n", + " # 'smooth_scale_1D':0.2\n", + " })\n", + " else:\n", + " if os.path.isfile(root_dir + '{}/{}/getdist_{}_cell.txt'.format(root, root, root))==False:\n", + " \n", + " samples = np.loadtxt(root_dir + '{}/{}/samples_{}_cell.txt'.format(root, root, root))\n", + " \n", + " if 'nautilus' in root:\n", + " weights = np.exp(samples[:, -3])\n", + " neglogL = samples[:, -2] - samples[:, -1]\n", + "\n", + " samples = np.column_stack((weights, neglogL, samples[:, 0:-3]))\n", + " elif 'mh' in root:\n", + " samples = np.column_stack((np.ones_like(samples[:,-1]),np.log(samples[:,-1])-np.log(samples[:,-2]), samples[:,0:-2]))\n", + " burnin=0.3\n", + " else:\n", + " print(\"here\")\n", + " samples = np.column_stack((samples[:,-1],samples[:,-3],samples[:,0:-4]))\n", + " \n", + " np.savetxt(root_dir + '{}/{}/getdist_{}_cell.txt'.format(root, root, root), samples)\n", + " \n", + " chain = g.samples_for_root(root_dir + '{}/{}/getdist_{}_cell'.format(root, root, root),\n", + " cache=False,\n", + " settings={'ignore_rows': burnin,\n", + " # 'smooth_scale_2D':0.2,\n", + " # 'smooth_scale_1D':0.2\n", + " })\n", + " p = chain.getParams()\n", + "\n", + " chains.append(chain)\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "51f60f61", + "metadata": {}, + "outputs": [], + "source": [ + "name_list = ['OMEGA_M','ombh2','h0','n_s','SIGMA_8','S_8','logt_agn','a','m1','bias_1', 'alpha', 'beta', 'omch2']\n", + "label_list = [r'\\Omega_{\\rm m}', r'\\omega_{\\rm b}', r'h', r'n_{\\rm s}', r'\\sigma_8', r'S_8', r'\\log T_{\\rm AGN}', r'A_{\\rm IA}', r'm_1', r'\\Delta z', r'\\alpha_{\\rm PSF}', r'\\beta_{\\rm PSF}', r'\\omega_{\\rm c}']\n", + "\n", + "for chain in chains:\n", + " param_names = chain.getParamNames()\n", + " p = chain.getParams()\n", + " for name, label in zip(name_list, label_list):\n", + " if hasattr(p,name):\n", + " param_names.parWithName(name).label = label\n", + " \n", + "legend_labels = list(roots.values())\n" + ] + }, + { + "cell_type": "markdown", + "id": "09ff24ef-6e8c-4ddd-96de-eeaf63b6982d", + "metadata": {}, + "source": [ + "## Plot the chains" + ] + }, + { + "cell_type": "markdown", + "id": "04fb3609", + "metadata": {}, + "source": [ + "### FIDUCIAL PLOT" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "dc86e03a", + "metadata": {}, + "outputs": [], + "source": [ + "%matplotlib inline\n", + "\n", + "colours = [\n", + " \"royalblue\",\n", + " \"orange\",\n", + " \"crimson\",\n", + " \"forestgreen\",\n", + " \"indigo\",\n", + "]\n", + "\n", + "linestyle = [\n", + " 'solid',\n", + " 'solid',\n", + " 'solid',\n", + " 'solid',\n", + " 'solid'\n", + "]\n", + "\n", + "line_args = [dict(color=col, ls=ls, lw=2) for col, ls in zip(colours, linestyle)]\n", + "\n", + "# FIDUCIAL PLOT\n", + "g.triangle_plot(chains,\n", + " ['SIGMA_8','S_8','OMEGA_M'], #\n", + " legend_labels=legend_labels,\n", + " line_args=line_args,\n", + " contour_colors=colours,\n", + " label_order=[1,0,2,3,4],\n", + " filled=[True,True,False,False,True])\n", + "\n", + "g.export('../Plots/SP_v1.4.6.3_B_fiducial_config_contour_plot.pdf')" + ] + }, + { + "cell_type": "markdown", + "id": "5f48f2e8", + "metadata": {}, + "source": [ + "### IA PLOT" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4d3a244d", + "metadata": {}, + "outputs": [], + "source": [ + "colours = [\n", + " \"orange\", \n", + " \"royalblue\",\n", + " \"forestgreen\",\n", + "]\n", + "\n", + "linestyle = [\n", + " 'solid',\n", + " 'solid',\n", + " 'solid',\n", + "]\n", + "\n", + "line_args = [dict(color=col, ls=ls, lw=2) for col, ls in zip(colours, linestyle)]\n", + "\n", + "g.triangle_plot(chains,\n", + " ['S_8','OMEGA_M','a'], #\n", + " legend_labels=legend_labels,\n", + " line_args=line_args,\n", + " contour_args={'alpha':0.6},\n", + " contour_colors=colours,\n", + " filled=[True, False, True])\n", + "\n", + "g.export('../Plots/SP_v1.4.6.3_B_fiducial_config_contour_plot_ia.pdf')" + ] + }, + { + "cell_type": "markdown", + "id": "df994437", + "metadata": {}, + "source": [ + "### PSF PLOT" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e16a4c90", + "metadata": {}, + "outputs": [], + "source": [ + "colours = [\n", + " \"royalblue\",\n", + " \"orange\", \n", + " \"hotpink\",\n", + " \"slategray\",\n", + "]\n", + "\n", + "linestyle = [\n", + " 'solid',\n", + " 'solid',\n", + " 'solid',\n", + " 'solid',\n", + "]\n", + "\n", + "line_args = [dict(color=col, ls=ls, lw=2) for col, ls in zip(colours, linestyle)]\n", + "\n", + "g.triangle_plot(chains,\n", + " ['S_8','OMEGA_M', 'alpha','beta'], #\n", + " legend_labels=legend_labels,\n", + " line_args=line_args,\n", + " contour_args=[{'alpha':1},{'alpha':0.6},{'alpha':0.8},{'alpha':0.8}],\n", + " contour_colors=colours,\n", + " legend_loc='upper right',\n", + " label_order=[1,0,2,3],\n", + " filled=[False, True, True, True])\n", + "\n", + "g.subplots[3,2].scatter(0.005,0.81, color='k', marker='X', s=400, label='Fiducial config best-fit')\n", + "g.subplots[3,2].scatter(0.022,0.798, color='k', marker='P', s=400, label='Fiducial config best-fit')\n", + "\n", + "g.export('../Plots/SP_v1.4.6.3_B_fiducial_config_contour_plot_psf.pdf')" + ] + }, + { + "cell_type": "markdown", + "id": "ed35ae74", + "metadata": {}, + "source": [ + "### DELTA Z PLOT" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "acfcdfb5", + "metadata": {}, + "outputs": [], + "source": [ + "colours = [\n", + " \"orange\", \n", + " \"royalblue\",\n", + " \"indigo\",\n", + "]\n", + "\n", + "linestyle = [\n", + " 'solid',\n", + " 'solid',\n", + " 'solid',\n", + "]\n", + "\n", + "line_args = [dict(color=col, ls=ls, lw=2) for col, ls in zip(colours, linestyle)]\n", + "g.triangle_plot(chains,\n", + " ['S_8','OMEGA_M', 'bias_1'], #\n", + " legend_labels=legend_labels,\n", + " line_args=line_args,\n", + " contour_args=[{'alpha':1.0},{'alpha':0.9},{'alpha':0.5}],\n", + " contour_colors=colours,\n", + " filled=[True, False, True])\n", + "\n", + "g.export('../Plots/SP_v1.4.6.3_B_fiducial_config_contour_plot_dz.pdf')" + ] + }, + { + "cell_type": "markdown", + "id": "698d6f8a", + "metadata": {}, + "source": [ + "### EXTERNAL DATA" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "638926dc", + "metadata": {}, + "outputs": [], + "source": [ + "colours = [\n", + " \"orange\", \n", + " \"royalblue\",\n", + " \"crimson\",\n", + " \"forestgreen\",\n", + "]\n", + "\n", + "linestyle = [\n", + " 'solid',\n", + " 'solid',\n", + " 'solid',\n", + " 'solid',\n", + " 'solid',\n", + "]\n", + "\n", + "line_args = [dict(color=col, ls=ls) for col, ls in zip(colours, linestyle)]\n", + "\n", + "g = plots.get_subplot_plotter(width_inch=10)\n", + "g.settings.axes_fontsize=25\n", + "g.settings.axes_labelsize=25\n", + "g.settings.legend_fontsize = 22\n", + "\n", + "g.plot_2d(chains,\n", + " ['S_8','OMEGA_M', 'SIGMA_8'], #\n", + " line_args=line_args,\n", + " # contour_colors=colours,\n", + " # legend_labels=legend_labels,\n", + " alphas=[0.7, 1.0, 1.0, 1.0],\n", + " filled=[True, True, True, False])\n", + "g.add_y_bands(0.2975, 0.0086, alpha2=0, color='k', label=\"BAO\")\n", + "g.add_legend(legend_labels, legend_loc='upper right')\n", + "\n", + "g.export('../Plots/SP_v1.4.6.3_B_fiducial_config_contour_plot_ext.pdf')" + ] + }, + { + "cell_type": "markdown", + "id": "ff19d475", + "metadata": {}, + "source": [ + "### Small scales" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "195ca137", + "metadata": {}, + "outputs": [], + "source": [ + "%matplotlib inline\n", + "\n", + "colours = [\n", + " \"orange\", \n", + " \"dodgerblue\", \n", + "]\n", + "\n", + "linestyle = [\n", + " 'solid',\n", + " 'solid',\n", + "]\n", + "\n", + "line_args = [dict(color=col, ls=ls) for col, ls in zip(colours, linestyle)]\n", + "\n", + "g = plots.get_subplot_plotter(width_inch=9)\n", + "g.settings.axes_fontsize=25\n", + "g.settings.axes_labelsize=25\n", + "g.settings.alpha_filled_add = 0.7\n", + "g.settings.legend_fontsize = 30\n", + "\n", + "g.plot_2d(chains,\n", + " ['S_8','OMEGA_M'], #\n", + " line_args=line_args,\n", + " contour_args=[{'alpha':0.7},{'alpha':1.0}],\n", + " contour_colors=colours,\n", + " filled=[True, True])\n", + "g.add_legend(legend_labels, legend_loc='upper right')\n", + "\n", + "g.export('../Plots/SP_v1.4.6.3_B_fiducial_config_contour_plot_scales.pdf')" + ] + }, + { + "cell_type": "markdown", + "id": "92cadb11", + "metadata": {}, + "source": [ + "### BBN Prior" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5a81c458", + "metadata": {}, + "outputs": [], + "source": [ + "%matplotlib inline\n", + "\n", + "from getdist.gaussian_mixtures import Gaussian1D\n", + "\n", + "colours = [\n", + " \"orange\", \n", + " \"royalblue\",\n", + "]\n", + "\n", + "linestyle = [\n", + " 'solid',\n", + " 'solid',\n", + "]\n", + "\n", + "line_args = [dict(color=col, ls=ls, lw=2) for col, ls in zip(colours, linestyle)]\n", + "\n", + "# BBN PRIOR\n", + "bbn_prior = Gaussian1D(mean=0.02218, sigma=0.00055, name='ombh2', labels=[r'\\omega_{\\rm b}'],label='BBN prior')\n", + "bbn_chain = bbn_prior.MCSamples(3000,label='BBN prior')\n", + "\n", + "g.triangle_plot(chains\n", + " +[bbn_chain]\n", + " ,\n", + " name_list,\n", + " legend_labels=legend_labels,\n", + " line_args=line_args,\n", + " contour_colors=colours,\n", + " filled=[True, False])\n" + ] + }, + { + "cell_type": "markdown", + "id": "34fcc96a", + "metadata": {}, + "source": [ + "## Plot the best-fit $\\xi_\\pm$" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5fe497bd", + "metadata": {}, + "outputs": [], + "source": [ + "xi_p_data = data['XI_PLUS'].data\n", + "xi_m_data = data['XI_MINUS'].data\n", + "cov_mat = data['COVMAT'].data\n", + "\n", + "labels = roots_scale.values()\n", + "\n", + "bbox_to_anchor_xip = (0.685, 0.09)\n", + "bbox_to_anchor_xim = (0.3, 0.65)\n", + "theta_min = 1.0\n", + "theta_max = 250.0\n", + "loc_legend = \"lower center\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7277e2ed", + "metadata": {}, + "outputs": [], + "source": [ + "colours = [\n", + " \"orange\",\n", + " \"dodgerblue\",\n", + "]\n", + "\n", + "linestyle = [\n", + " 'solid',\n", + " 'solid',\n", + "]\n", + "\n", + "line_args = [dict(color=col, ls=ls, lw=2) for col, ls in zip(colours, linestyle)]\n", + "\n", + "labels = roots_scale.values()\n", + "\n", + "fig, ax = plt.subplots(1, 1, figsize=(11, 7))\n", + "\n", + "theta, xi_p, xi_m = xi_p_data['ANG'], xi_p_data['VALUE'], xi_m_data['VALUE']\n", + "ax.errorbar(theta, theta*xi_p, yerr=theta*np.sqrt(np.diag(cov_mat[:len(theta),:len(theta)])), fmt='o', color='black', capsize=2)\n", + "\n", + "for idx, (label, root) in enumerate(zip(labels, roots_scale)):\n", + " #Read the results\n", + " theta = (np.loadtxt(path_output_chains + '{}/best_fit/shear_xi_plus/theta.txt'.format(root))) * 180/np.pi * 60\n", + " xi_plus = np.loadtxt(path_output_chains + '{}/best_fit/shear_xi_plus/bin_1_1.txt'.format(root))\n", + " xi_minus = np.loadtxt(path_output_chains + '{}/best_fit/shear_xi_minus/bin_1_1.txt'.format(root))\n", + " xi_sys_plus = np.loadtxt(path_output_chains + '{}/best_fit/xi_sys/shear_xi_plus.txt'.format(root))\n", + " xi_sys_minus = np.loadtxt(path_output_chains + '{}/best_fit/xi_sys/shear_xi_minus.txt'.format(root))\n", + " theta_xi_sys = np.loadtxt(path_output_chains + '{}/best_fit/xi_sys/theta.txt'.format(root)) * 180/np.pi * 60\n", + " \n", + " xi_sys_plus = np.interp(theta, theta_xi_sys, xi_sys_plus)\n", + " xi_sys_minus = np.interp(theta, theta_xi_sys, xi_sys_minus)\n", + " xi_plus += xi_sys_plus\n", + " xi_minus += xi_sys_minus\n", + "\n", + " mask = (theta > theta_min) & (theta < theta_max)\n", + " theta = theta[mask]\n", + " ax.plot(theta, theta*xi_plus[mask], label=label, **line_args[idx])\n", + "\n", + "ymin = ax.get_ylim()[0]\n", + "ymax = ax.get_ylim()[1]\n", + "\n", + "ax.fill_betweenx(y=[ymin, ymax], x1=0, x2=12, color='gray', alpha=0.2)\n", + "ax.fill_betweenx(y=[ymin, ymax], x1=0, x2=5, color='gray', alpha=0.7)\n", + "ax.fill_betweenx(y=[ymin, ymax], x1=83, x2=300, color='gray', alpha=0.2)\n", + "\n", + "ax.set_ylim(ymin, ymax)\n", + "\n", + "ax.set_ylabel(r'$\\theta \\xi_\\pm$', fontsize=26)\n", + "ax.set_xlabel(r'$\\theta$ (arcmin)', fontsize=26)\n", + "ax.set_xlim([theta.min()-0.1, theta.max()+20])\n", + "ax.set_title(r'$\\xi_+(\\theta)$', fontsize=26)\n", + "ax.set_xscale('log')\n", + "ax.set_xticks(np.array([1, 10, 100]))\n", + "ax.tick_params(axis=\"x\", which=\"minor\", length=2, width=0.8)\n", + "ax.tick_params(axis='both', which='major', labelsize=24)\n", + "ax.tick_params(axis='both', which='minor', labelsize=20)\n", + "ax.yaxis.get_offset_text().set_fontsize(24)\n", + "ax.ticklabel_format(axis='y', style='sci', scilimits=(0,0))\n", + "ax.legend(loc=loc_legend, bbox_to_anchor=bbox_to_anchor_xip, fontsize=20)\n", + "\n", + "\n", + "plt.savefig(\"./../Plots/scale_cut_xipm_SP_v1.4.6.3_B.pdf\", bbox_inches='tight')\n", + "\n", + "plt.show()\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a8c70d3a", + "metadata": {}, + "outputs": [], + "source": [ + "\n", + "labels = roots_nonlin.values()\n", + "\n", + "colours = [\n", + " \"orange\",\n", + " \"hotpink\",\n", + " 'teal'\n", + "]\n", + "\n", + "linestyle = [\n", + " 'solid',\n", + " 'solid',\n", + " 'dashed'\n", + "]\n", + "\n", + "line_args = [dict(color=col, ls=ls, lw=2) for col, ls in zip(colours, linestyle)]\n", + "\n", + "fig, [ax,ax2] = plt.subplots(2, 1, figsize=(11, 14))\n", + "\n", + "theta, xi_p, xi_m = xi_p_data['ANG'], xi_p_data['VALUE'], xi_m_data['VALUE']\n", + "ax.errorbar(theta, theta*xi_p, yerr=theta*np.sqrt(np.diag(cov_mat[:len(theta),:len(theta)])), fmt='o', color='black', capsize=2)\n", + "ax2.errorbar(theta, theta*xi_m, yerr=theta*np.sqrt(np.diag(cov_mat[len(theta):2*len(theta),len(theta):2*len(theta)])), fmt='o', color='black', capsize=2)\n", + "\n", + "for idx, (label, root) in enumerate(zip(labels, roots_nonlin)):\n", + " #Read the results\n", + " theta = (np.loadtxt(path_output_chains + '{}/best_fit/shear_xi_plus/theta.txt'.format(root))) * 180/np.pi * 60\n", + " xi_plus = np.loadtxt(path_output_chains + '{}/best_fit/shear_xi_plus/bin_1_1.txt'.format(root))\n", + " xi_minus = np.loadtxt(path_output_chains + '{}/best_fit/shear_xi_minus/bin_1_1.txt'.format(root))\n", + " xi_sys_plus = np.loadtxt(path_output_chains + '{}/best_fit/xi_sys/shear_xi_plus.txt'.format(root))\n", + " xi_sys_minus = np.loadtxt(path_output_chains + '{}/best_fit/xi_sys/shear_xi_minus.txt'.format(root))\n", + " theta_xi_sys = np.loadtxt(path_output_chains + '{}/best_fit/xi_sys/theta.txt'.format(root)) * 180/np.pi * 60\n", + " \n", + " xi_sys_plus = np.interp(theta, theta_xi_sys, xi_sys_plus)\n", + " xi_sys_minus = np.interp(theta, theta_xi_sys, xi_sys_minus)\n", + " xi_plus += xi_sys_plus\n", + " xi_minus += xi_sys_minus\n", + "\n", + " mask = (theta > theta_min) & (theta < theta_max)\n", + " theta = theta[mask]\n", + " ax.plot(theta, theta*xi_plus[mask], label=label, **line_args[idx])\n", + " ax2.plot(theta, theta*xi_minus[mask], label=label, **line_args[idx])\n", + "\n", + "ymin = ax.get_ylim()[0]\n", + "ymax = ax.get_ylim()[1]\n", + "ax.fill_betweenx(y=[ymin, ymax], x1=0, x2=12, color='gray', alpha=0.2)\n", + "ax.fill_betweenx(y=[ymin, ymax], x1=83, x2=300, color='gray', alpha=0.2)\n", + "\n", + "ax.set_ylim(ymin, ymax)\n", + "\n", + "ax.set_ylabel(r'$\\theta \\xi_\\pm$', fontsize=26)\n", + "ax.set_xlabel(r'$\\theta$ (arcmin)', fontsize=26)\n", + "ax.set_xlim([theta.min()-0.1, theta.max()+20])\n", + "ax.set_title(r'$\\xi_+(\\theta)$', fontsize=26)\n", + "ax.set_xscale('log')\n", + "ax.set_xticks(np.array([1, 10, 100]))\n", + "ax.tick_params(axis=\"x\", which=\"minor\", length=2, width=0.8)\n", + "ax.tick_params(axis='both', which='major', labelsize=24)\n", + "ax.tick_params(axis='both', which='minor', labelsize=20)\n", + "ax.yaxis.get_offset_text().set_fontsize(24)\n", + "ax.ticklabel_format(axis='y', style='sci', scilimits=(0,0))\n", + "\n", + "\n", + "ymin = ax2.get_ylim()[0]\n", + "ymax = ax2.get_ylim()[1]\n", + "ax2.fill_betweenx(y=[ymin, ymax], x1=0, x2=12, color='gray', alpha=0.2)\n", + "ax2.fill_betweenx(y=[ymin, ymax], x1=83, x2=3000, color='gray', alpha=0.2)\n", + "\n", + "ax2.set_ylim(ymin, ymax)\n", + "ax2.set_xlabel(r'$\\theta$ (arcmin)', fontsize=26)\n", + "ax2.set_xlim([theta.min()-0.1, theta.max()])\n", + "ax2.set_xscale('log')\n", + "ax2.set_title(r'$\\xi_-(\\vartheta)$', fontsize=26)\n", + "ax2.set_xticks(np.array([1, 10, 100]))\n", + "ax2.tick_params(axis=\"x\", which=\"minor\", length=2, width=0.8)\n", + "ax2.tick_params(axis='both', which='major', labelsize=24)\n", + "ax2.tick_params(axis='both', which='minor', labelsize=20)\n", + "ax2.yaxis.get_offset_text().set_fontsize(24)\n", + "ax2.ticklabel_format(axis='y', style='sci', scilimits=(0,0))\n", + "ax2.legend(loc=loc_legend, bbox_to_anchor=bbox_to_anchor_xim, fontsize=20)\n", + "\n", + "plt.savefig(\"./../Plots/nonlin_xipm_SP_v1.4.6.3_B.pdf\", bbox_inches='tight')\n", + "\n", + "plt.show()\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f270042c", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "my_env", + "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.10.13" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/cosmo_inference/notebooks/2D_cosmic_shear_configuration_plots/get_chi2.ipynb b/cosmo_inference/notebooks/2D_cosmic_shear_configuration_plots/get_chi2.ipynb new file mode 100644 index 00000000..b505ea33 --- /dev/null +++ b/cosmo_inference/notebooks/2D_cosmic_shear_configuration_plots/get_chi2.ipynb @@ -0,0 +1,577 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import configparser\n", + "import subprocess\n", + "import re\n", + "from getdist import plots, loadMCSamples\n", + "from astropy.io import fits\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "from scipy.interpolate import interp1d\n", + "import scipy.stats as stats\n", + "from IPython.display import Markdown, display\n", + "import healpy as hp\n", + "\n", + "import sys\n", + "sys.path.append(\"/home/guerrini/sp_validation/cosmo_inference/scripts\")\n", + "\n", + "import chain_postprocessing\n", + "\n", + "%matplotlib inline\n", + "\n", + "plt.rc('mathtext', fontset='stix')\n", + "plt.rc('font', family='sans-serif')\n", + "\n", + "g = plots.get_subplot_plotter(width_inch=30)\n", + "g.settings.axes_fontsize=30\n", + "g.settings.axes_labelsize=30\n", + "g.settings.alpha_filled_add = 0.7\n", + "g.settings.legend_fontsize = 40\n", + "\n", + "# #SPECIFY DATA DIRECTORY AND DESIRED CHAINS TO ANALYSE\n", + "root_dir = '/n09data/guerrini/output_chains/'\n", + "blind = 'B'\n", + "\n", + "roots = [\n", + "f'SP_v1.4.6.3_{blind}_fiducial_config',\n", + "f'SP_v1.4.6.3_{blind}_small_scales_config',\n", + "f'SP_v1.4.6.3_{blind}_flat_alpha_beta_config',\n", + "f'SP_v1.4.6.3_{blind}_no_xi_sys_config',\n", + "f'SP_v1.4.6.3_{blind}_no_leak_corr_config',\n", + "f'SP_v1.4.6.3_{blind}_flat_delta_z_config',\n", + "f'SP_v1.4.6.3_{blind}_no_delta_z_config',\n", + "f'SP_v1.4.6.3_{blind}_flat_ia_config',\n", + "f'SP_v1.4.6.3_{blind}_no_ia_config',\n", + "f'SP_v1.4.6.3_{blind}_no_m_bias_config',\n", + "f'SP_v1.4.6.3_{blind}_unmasked_covmat_config',\n", + "f'SP_v1.4.6.3_{blind}_halofit_config',\n", + "f'SP_v1.4.6.3_{blind}_no_baryons_config',\n", + "f'SP_v1.4.6.3_{blind}_nautilus_config',\n", + "f'SP_v1.4.6.3_{blind}_planck_config',\n", + "f'SP_v1.4.6.3_{blind}_planck_desi_config',\n", + "]\n", + "\n", + "catalog_versions = [\n", + " f'SP_v1.4.6.3_config/SP_v1.4.6.3_{blind}',\n", + "]\n", + "\n", + "catalog_sub_versions = [\n", + " f'SP_v1.4.6.3_leak_corr_{blind}_masked',\n", + " f'SP_v1.4.6.3_leak_corr_{blind}_masked',\n", + " f'SP_v1.4.6.3_leak_corr_{blind}_masked',\n", + " f'SP_v1.4.6.3_leak_corr_{blind}_masked',\n", + " f'SP_v1.4.6.3_{blind}_masked',\n", + " f'SP_v1.4.6.3_leak_corr_{blind}_masked',\n", + " f'SP_v1.4.6.3_leak_corr_{blind}_masked',\n", + " f'SP_v1.4.6.3_leak_corr_{blind}_masked',\n", + " f'SP_v1.4.6.3_leak_corr_{blind}_masked',\n", + " f'SP_v1.4.6.3_leak_corr_{blind}_masked',\n", + " f'SP_v1.4.6.3_leak_corr_{blind}',\n", + " f'SP_v1.4.6.3_leak_corr_{blind}_masked',\n", + " f'SP_v1.4.6.3_leak_corr_{blind}_masked',\n", + " f'SP_v1.4.6.3_leak_corr_{blind}_masked',\n", + " f'SP_v1.4.6.3_leak_corr_{blind}_masked',\n", + " f'SP_v1.4.6.3_leak_corr_{blind}_masked',\n", + "]\n", + "output_folder = '/n09data/guerrini/output_chains/'\n", + "\n", + "path_ini_files = '/home/guerrini/sp_validation/cosmo_inference/cosmosis_config/'\n", + "\n", + "\n", + "ini_roots =[\n", + " f'blind_{blind}/fiducial',\n", + " f'blind_{blind}/small_scales',\n", + " f'blind_{blind}/flat_alpha_beta',\n", + " f'blind_{blind}/no_xi_sys',\n", + " f'blind_{blind}/no_leak_corr',\n", + " f'blind_{blind}/flat_delta_z',\n", + " f'blind_{blind}/no_delta_z',\n", + " f'blind_{blind}/flat_ia',\n", + " f'blind_{blind}/no_ia',\n", + " f'blind_{blind}/no_m_bias',\n", + " f'blind_{blind}/unmasked_covmat',\n", + " f'blind_{blind}/halofit',\n", + " f'blind_{blind}/no_baryons',\n", + " f'blind_{blind}/nautilus',\n", + " f'blind_{blind}/planck',\n", + " f'blind_{blind}/planck_desi',\n", + "]\n", + "\n", + "properties = {}\n", + "\n", + "for i,root in enumerate(roots):\n", + " print(root)\n", + " config = configparser.ConfigParser()\n", + " config.optionxform = str # Preserve case sensitivity of option names\n", + " config.read(path_ini_files+'config_space_v1.4.6.3_fiducial/pipeline/'+ini_roots[i]+'.ini') \n", + " add_xi_sys = config[\"2pt_like\"][\"add_xi_sys\"]\n", + " lower_bound_xi_plus, upper_bound_xi_plus = map(float, config[\"2pt_like\"][\"angle_range_XI_PLUS_1_1\"].split())\n", + " lower_bound_xi_minus, upper_bound_xi_minus = map(float, config[\"2pt_like\"][\"angle_range_XI_MINUS_1_1\"].split())\n", + "\n", + " properties[root] = {\n", + " 'add_xi_sys': add_xi_sys,\n", + " 'lower_bound_xi_plus': lower_bound_xi_plus,\n", + " 'upper_bound_xi_plus': upper_bound_xi_plus,\n", + " 'lower_bound_xi_minus': lower_bound_xi_minus,\n", + " 'upper_bound_xi_minus': upper_bound_xi_minus\n", + " }\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Retrieve the chains" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#READ CHAIN\n", + "\n", + "chains=[]\n", + "\n", + "for i, root in enumerate(roots):\n", + " burnin = 0\n", + " \n", + " if os.path.isfile(root_dir + '{}/getdist_{}.txt'.format(root, root))==False:\n", + " \n", + " samples = np.loadtxt(root_dir + '{}/samples_{}.txt'.format(root, root))\n", + " \n", + " if 'nautilus' in root:\n", + " samples = np.column_stack((np.exp(samples[:,-3]),samples[:,-1]-samples[:,-2],samples[:,0:-3]))\n", + " if 'mh' in root:\n", + " samples = np.column_stack((np.ones_like(samples[:,-1]),np.log(samples[:,-1])-np.log(samples[:,-2]), samples[:,0:-2]))\n", + " burnin=0.3\n", + " else:\n", + " samples = np.column_stack((samples[:,-1],samples[:,-3],samples[:,0:-4]))\n", + " \n", + " np.savetxt(root_dir + '{}/getdist_{}.txt'.format(root, root), samples)\n", + " \n", + " chain = g.samples_for_root(root_dir + '{}/getdist_{}'.format(root, root),\n", + " cache=False,\n", + " settings={'ignore_rows': burnin,\n", + " 'smooth_scale_2D':0.5,\n", + " 'smooth_scale_1D':0.5\n", + " })\n", + " p = chain.getParams()\n", + "\n", + " chains.append(chain)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "param_list = ['OMEGA_M','ombh2','h0','n_s','SIGMA_8','s_8_input', 'logt_agn','a','m1','bias_1','alpha','beta', 'omch2', 'm', 'a_planck']\n", + "label_list = ['\\Omega_m', '\\omega_b', 'h_0', 'n_s', '\\sigma_8', 'S_8', 'log T_{AGN}', 'A_{IA}', 'm_1', '\\Delta z_1', '\\\\alpha_{PSF}', '\\\\beta_{PSF}', '\\omega_c', 'M', 'A_{\\rm Planck}']\n", + "\n", + "for chain in chains:\n", + " param_names = chain.getParamNames()\n", + " for name, label in zip(param_list, label_list):\n", + " if param_names.parWithName(name) is not None:\n", + " param_names.parWithName(name).label = label\n", + " " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Extract the best fit parameters" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "best_fit = {}\n", + "\n", + "for root, chain in zip(roots, chains):\n", + " print(root)\n", + " p=chain.getParams()\n", + " \n", + " best_fit[root] = chain_postprocessing.extract_best_fit_params(chain, best_fit_method='2Dkde')\n", + " " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Run `Cosmosis` in test mode to get the data vectors" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "if not os.path.exists(path_ini_files+'/values_empty.ini'):\n", + " content = \"\"\"[cosmological_parameters]\n", + "\n", + "tau = 0.0544\n", + "w = -1.0\n", + "mnu = 0.06\n", + "omega_k = 0.0\n", + "wa = 0.0\n", + "\n", + "[halo_model_parameters]\n", + "\n", + "[intrinsic_alignment_parameters]\n", + "\n", + "[shear_calibration_parameters]\n", + "\n", + "[nofz_shifts]\n", + "\n", + "[psf_leakage_parameters]\n", + "\"\"\"\n", + "\n", + " with open(path_ini_files+'/values_empty.ini', 'w') as f:\n", + " f.write(content)\n", + " f.close()\n", + "\n", + " print('File created successfully')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "section_map = {\n", + " 'omch2': 'cosmological_parameters',\n", + " 'ombh2': 'cosmological_parameters',\n", + " 'h0': 'cosmological_parameters',\n", + " 'n_s': 'cosmological_parameters',\n", + " 's_8_input': 'cosmological_parameters',\n", + " 'logt_agn': 'halo_model_parameters',\n", + " 'a': 'intrinsic_alignment_parameters',\n", + " 'm1': 'shear_calibration_parameters',\n", + " 'bias_1': 'nofz_shifts',\n", + " 'alpha': 'psf_leakage_parameters',\n", + " 'beta': 'psf_leakage_parameters',\n", + " 'm': 'supernova_params',\n", + " 'a_planck' : 'planck'\n", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "env = os.environ.copy()\n", + "env[\"LD_LIBRARY_PATH\"] = \"/home/guerrini/.conda/envs/sp_validation/lib/python3.9/site-packages/cosmosis/datablock:\" + env.get(\"LD_LIBRARY_PATH\", \"\")\n", + "\n", + "for i,root in enumerate(roots):\n", + " print(root)\n", + " config = configparser.ConfigParser()\n", + " config.optionxform = str # Preserve case sensitivity of option names\n", + "\n", + " for param, section in section_map.items():\n", + " # Check if this parameter exists for the current root\n", + " if param in best_fit[root]:\n", + " value = best_fit[root][param]\n", + " \n", + " if section not in config:\n", + " config.add_section(section)\n", + "\n", + " config[section][param] = str(value)\n", + "\n", + " with open(path_ini_files+'/values_empty.ini', 'w') as configfile:\n", + " config.write(configfile)\n", + "\n", + " #Modify the ini file to run in test mode at the best fit\n", + " config = configparser.ConfigParser()\n", + " config.optionxform = str # Preserve case sensitivity of option names\n", + " \n", + " ini_file = path_ini_files+'config_space_v1.4.6.3_fiducial/pipeline/{}.ini'.format(ini_roots[i])\n", + " config.read(ini_file)\n", + "\n", + " sampler = config['runtime']['sampler']\n", + " config['runtime']['sampler'] = 'test'\n", + " values = config['pipeline']['values']\n", + " config['pipeline']['values'] = path_ini_files + '/values_empty.ini'\n", + " config['DEFAULT']['FITS_FILE'] = f'/home/guerrini/sp_validation/cosmo_inference/data/{catalog_versions[0]}/cosmosis_{catalog_sub_versions[i]}.fits'\n", + " config['test']['save_dir'] = root_dir + '{}/best_fit'.format(root)\n", + " \n", + " with open(ini_file, 'w') as configfile:\n", + " config.write(configfile)\n", + "\n", + " #Run cosmosis\n", + " result = subprocess.run(\n", + " ['cosmosis', ini_file],\n", + " env=env,\n", + " capture_output=True,\n", + " text=True\n", + " )\n", + " print(f\"STDOUT:\\n{result.stdout}\")\n", + " print(f\"STDERR:\\n{result.stderr}\")\n", + "\n", + " #Modify the ini file to the previous one\n", + " config['pipeline']['values'] = values\n", + " config['runtime']['sampler'] = sampler\n", + "\n", + " with open(ini_file, 'w') as configfile:\n", + " config.write(configfile)\n", + " " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Compute the $\\chi^2$" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "\n", + "metrics = {}\n", + "\n", + "for idx,root in enumerate(roots):\n", + " print(root)\n", + " match = re.search(r'corr_([A-Za-z])', root)\n", + " if match:\n", + " blind = match.group(1)\n", + "\n", + " add_xi_sys = properties[root]['add_xi_sys']\n", + " print(f\"add_xi_sys: {add_xi_sys}\")\n", + " lower_bound_xi_plus = properties[root]['lower_bound_xi_plus']\n", + " upper_bound_xi_plus = properties[root]['upper_bound_xi_plus']\n", + " lower_bound_xi_minus = properties[root]['lower_bound_xi_minus']\n", + " upper_bound_xi_minus = properties[root]['upper_bound_xi_minus']\n", + "\n", + " #Read the results\n", + " theta = np.loadtxt(output_folder + '{}/best_fit/shear_xi_plus/theta.txt'.format(root))\n", + " theta_arcmin = theta * 180 * 60 / np.pi\n", + " shear_xi_plus = np.loadtxt(output_folder + '{}/best_fit/shear_xi_plus/bin_1_1.txt'.format(root))\n", + " shear_xi_minus = np.loadtxt(output_folder + '{}/best_fit/shear_xi_minus/bin_1_1.txt'.format(root))\n", + " \n", + " if add_xi_sys == 'T':\n", + " xi_sys_plus = np.loadtxt(output_folder + '{}/best_fit/xi_sys/shear_xi_plus.txt'.format(root))\n", + " xi_sys_minus = np.loadtxt(output_folder + '{}/best_fit/xi_sys/shear_xi_minus.txt'.format(root))\n", + "\n", + " theta_tau = np.loadtxt(output_folder + '{}/best_fit/tau_0_plus/theta.txt'.format(root))\n", + " theta_tau_arcmin = theta_tau * 180 * 60 / np.pi\n", + " tau_0_model = np.loadtxt(output_folder + '{}/best_fit/tau_0_plus/bin_1_1.txt'.format(root))\n", + " tau_2_model = np.loadtxt(output_folder + '{}/best_fit/tau_2_plus/bin_1_1.txt'.format(root))\n", + "\n", + " data = fits.open(f'/home/guerrini/sp_validation/cosmo_inference/data/{catalog_versions[0]}/cosmosis_{catalog_sub_versions[idx]}.fits')\n", + " \n", + " tau_0_data = data['TAU_0_PLUS'].data['VALUE']\n", + " tau_2_data = data['TAU_2_PLUS'].data['VALUE']\n", + "\n", + " theta_data = data['XI_PLUS'].data['ANG']\n", + " xi_plus_data = data['XI_PLUS'].data['VALUE']\n", + " xi_minus_data = data['XI_MINUS'].data['VALUE']\n", + "\n", + "\n", + " #Load the covariance\n", + " cov = data['COVMAT'].data\n", + " cov_xi = cov[0:2*len(xi_plus_data), 0:2*len(xi_plus_data)]\n", + " cov_tau = cov[2*len(xi_plus_data):, 2*len(xi_plus_data):]\n", + "\n", + " #interpolate the model\n", + " interp_xi_plus = interp1d(theta_arcmin, shear_xi_plus, kind='cubic', fill_value='extrapolate')\n", + " interp_xi_minus = interp1d(theta_arcmin, shear_xi_minus, kind='cubic', fill_value='extrapolate')\n", + "\n", + " xi_plus_model = interp_xi_plus(theta_data)\n", + " if add_xi_sys:\n", + " xi_plus_model += xi_sys_plus\n", + " xi_minus_model = interp_xi_minus(theta_data)\n", + " if add_xi_sys:\n", + " xi_minus_model += xi_sys_minus\n", + "\n", + " #Concatenate the data vector\n", + " xi_data = np.concatenate((xi_plus_data, xi_minus_data))\n", + " xi_model = np.concatenate((xi_plus_model, xi_minus_model))\n", + "\n", + " tau_data = np.concatenate((tau_0_data, tau_2_data))\n", + " tau_model = np.concatenate((tau_0_model, tau_2_model))\n", + "\n", + " #Apply scale cuts\n", + " mask_xi_plus = (theta_data > lower_bound_xi_plus) & (theta_data < upper_bound_xi_plus)\n", + " mask_xi_minus = (theta_data > lower_bound_xi_minus) & (theta_data < upper_bound_xi_minus)\n", + " mask = np.concatenate((mask_xi_plus, mask_xi_minus))\n", + "\n", + " xi_data = xi_data[mask]\n", + " xi_model = xi_model[mask]\n", + " cov_xi = cov_xi[mask][:, mask]\n", + " \n", + " cov_xi_plus = cov[0:len(xi_plus_data), 0:len(xi_plus_data)]\n", + " cov_xi_plus = cov_xi_plus[mask_xi_plus][:, mask_xi_plus]\n", + " cov_xi_minus = cov[len(xi_plus_data):2*len(xi_minus_data), len(xi_plus_data):2*len(xi_minus_data)]\n", + " cov_xi_minus = cov_xi_minus[mask_xi_minus][:, mask_xi_minus]\n", + "\n", + " xi_plus_chi2 = np.dot((xi_plus_model[mask_xi_plus] - xi_plus_data[mask_xi_plus]), np.dot(np.linalg.inv(cov_xi_plus), (xi_plus_model[mask_xi_plus] - xi_plus_data[mask_xi_plus])))\n", + " xi_minus_chi2 = np.dot((xi_minus_model[mask_xi_minus] - xi_minus_data[mask_xi_minus]), np.dot(np.linalg.inv(cov_xi_minus), (xi_minus_model[mask_xi_minus] - xi_minus_data[mask_xi_minus])))\n", + " xi_chi2 = np.dot((xi_model - xi_data), np.dot(np.linalg.inv(cov_xi), (xi_model - xi_data)))\n", + " tau_chi2 = np.dot((tau_model - tau_data), np.dot(np.linalg.inv(cov_tau), (tau_model - tau_data)))\n", + " n_dof_xi_plus = np.sum(mask_xi_plus)\n", + " n_dof_xi_minus = np.sum(mask_xi_minus)\n", + " n_dof_tau = len(tau_0_data) + len(tau_2_data)\n", + " p_value_xi_plus = 1 - stats.chi2.cdf(xi_plus_chi2, n_dof_xi_plus)\n", + " p_value_xi_minus = 1 - stats.chi2.cdf(xi_minus_chi2, n_dof_xi_minus)\n", + " p_value_xi = 1 - stats.chi2.cdf(xi_chi2, n_dof_xi_plus + n_dof_xi_minus)\n", + " p_value_tau = 1 - stats.chi2.cdf(tau_chi2, n_dof_tau)\n", + " chi2_tot = xi_plus_chi2 + xi_minus_chi2 + tau_chi2\n", + " n_dof_tot = n_dof_xi_plus + n_dof_xi_minus + n_dof_tau\n", + " p_value_tot = 1 - stats.chi2.cdf(chi2_tot, n_dof_tot)\n", + "\n", + " metrics[root] = {\n", + " 'chi2_xi_plus': xi_plus_chi2,\n", + " 'n_dof_xi_plus': n_dof_xi_plus,\n", + " 'p_value_xi_plus': p_value_xi_plus,\n", + " 'chi2_xi_minus': xi_minus_chi2,\n", + " 'n_dof_xi_minus': n_dof_xi_minus,\n", + " 'p_value_xi_minus': p_value_xi_minus,\n", + " 'chi2_xi': xi_chi2,\n", + " 'p_value_xi': p_value_xi,\n", + " 'chi2_tau': tau_chi2,\n", + " 'n_dof_tau': n_dof_tau,\n", + " 'p_value_tau': p_value_tau,\n", + " 'chi2_tot': chi2_tot,\n", + " 'n_dof_tot': n_dof_tot,\n", + " 'p_value_tot': p_value_tot\n", + " }\n", + " print(\"Done!\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def get_latex_table(metrics):\n", + " latex_lines = [\n", + " r\"\\begin{tabular}{lccc|ccc|ccc}\",\n", + " r\"\\hline\",\n", + " r\"Root & $\\chi^2_{\\xi^+}$/dof & $p_{\\xi^+}$ & $\\chi^2_{\\xi^-}$/dof & $p_{\\xi^+}$ & $\\chi^2_{\\xi}$/dof & $p_{\\xi}$ &\"\n", + " r\"$\\chi^2_\\tau$/dof & $p_\\tau$ & $\\chi^2_{\\text{tot}}$/dof & $p_{\\text{tot}}$ \\\\\",\n", + " r\"\\hline\"\n", + " ]\n", + "\n", + " for root, vals in metrics.items():\n", + " escaped = root.replace(\"_\", r\"\\_\")\n", + " line = (\n", + " f\"{escaped} & \"\n", + " f\"{vals['chi2_xi_plus']:.2f}/{vals['n_dof_xi_plus']} & {vals['p_value_xi_plus']:.3g} & \"\n", + " f\"{vals['chi2_xi_minus']:.2f}/{vals['n_dof_xi_minus']} & {vals['p_value_xi_minus']:.3g} & \"\n", + " f\"{vals['chi2_xi']:.2f}/{vals['n_dof_xi_plus']+ vals['n_dof_xi_minus']} & {vals['p_value_xi']:.3g} &\"\n", + " f\"{vals['chi2_tau']:.2f}/{vals['n_dof_tau']} & {vals['p_value_tau']:.3g} & \"\n", + " f\"{vals['chi2_tot']:.2f}/{vals['n_dof_tot']} & {vals['p_value_tot']:.3g} \\\\\\\\\"\n", + " )\n", + " latex_lines.append(line)\n", + "\n", + " latex_lines.append(r\"\\hline\")\n", + " latex_lines.append(r\"\\end{tabular}\")\n", + "\n", + " # Print LaTeX table\n", + " print(\"\\n\".join(latex_lines))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "get_latex_table(metrics)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def display_markdown(metrics):\n", + " # Build Markdown table\n", + " header = (\n", + " \"| Root | $\\chi^2$ (ξ⁺) / dof | p-val (ξ⁺) |$\\chi^2$ (ξ-) / dof | p-val (ξ-) | $\\chi^2$ (ξ) / dof | p-val (ξ) | $\\chi^2$ (τ) / dof | p-val (τ) | $\\chi^2$ (tot) / dof | p-val (tot) |\\n\"\n", + " \"|------|----------------|------------|----------------|------------|------------|---------------|------------|------------|------------------|--------------|\\n\"\n", + " )\n", + "\n", + " rows = []\n", + " for root, vals in metrics.items():\n", + " row = f\"| `{root}` \"\n", + " row += f\"| {vals['chi2_xi_plus']:.2f} / {vals['n_dof_xi_plus']} \"\n", + " row += f\"| {vals['p_value_xi_plus']:.5f} \"\n", + " row += f\"| {vals['chi2_xi_minus']:.2f} / {vals['n_dof_xi_minus']} \"\n", + " row += f\"| {vals['p_value_xi_minus']:.5f} \"\n", + " row += f\"| {vals['chi2_xi']:.2f} / {vals['n_dof_xi_minus']+vals['n_dof_xi_plus']} \"\n", + " row += f\"| {vals['p_value_xi']:.5f} \"\n", + " row += f\"| {vals['chi2_tau']:.2f} / {vals['n_dof_tau']} \"\n", + " row += f\"| {vals['p_value_tau']:.5f} \"\n", + " row += f\"| {vals['chi2_tot']:.2f} / {vals['n_dof_tot']} \"\n", + " row += f\"| {vals['p_value_tot']:.5f} |\"\n", + " rows.append(row)\n", + "\n", + " # Display in Jupyter\n", + " display(Markdown(header + \"\\n\".join(rows)))\n", + " return header + \"\\n\".join(rows)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "markdown_source = display_markdown(metrics)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "my_env", + "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.10.13" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/cosmo_inference/notebooks/2D_cosmic_shear_configuration_plots/get_chi2_glass_mock.ipynb b/cosmo_inference/notebooks/2D_cosmic_shear_configuration_plots/get_chi2_glass_mock.ipynb new file mode 100644 index 00000000..1061e48a --- /dev/null +++ b/cosmo_inference/notebooks/2D_cosmic_shear_configuration_plots/get_chi2_glass_mock.ipynb @@ -0,0 +1,545 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import configparser\n", + "import subprocess\n", + "import re\n", + "from getdist import plots, loadMCSamples\n", + "from astropy.io import fits\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "from scipy.interpolate import interp1d\n", + "import scipy.stats as stats\n", + "from IPython.display import Markdown, display\n", + "import healpy as hp\n", + "# Make the plot\n", + "import seaborn as sns\n", + "from scipy.stats import chi2\n", + "\n", + "\n", + "import sys\n", + "sys.path.append(\"/home/guerrini/sp_validation/cosmo_inference/scripts\")\n", + "\n", + "import chain_postprocessing\n", + "\n", + "%matplotlib inline\n", + "\n", + "plt.style.use(\n", + " \"/home/guerrini/matplotlib_config/paper.mplstyle\"\n", + ")\n", + "\n", + "plt.rcParams['axes.labelsize'] = 18\n", + "plt.rcParams['xtick.labelsize'] = 18\n", + "plt.rcParams['ytick.labelsize'] = 18\n", + "\n", + "plt.rcParams['text.usetex'] = True\n", + "\n", + "g = plots.get_subplot_plotter(width_inch=30)\n", + "g.settings.axes_fontsize=30\n", + "g.settings.axes_labelsize=30\n", + "g.settings.alpha_filled_add = 0.7\n", + "g.settings.legend_fontsize = 40\n", + "\n", + "# #SPECIFY DATA DIRECTORY AND DESIRED CHAINS TO ANALYSE\n", + "\n", + "root_dir = \"/n09data/guerrini/glass_mock_chains/\"\n", + "\n", + "# Version of the glass mock chain run\n", + "chain_version = \"v6\"\n", + "\n", + "# Path to the glass mock data vectors\n", + "root_glass_dv = f\"/home/guerrini/sp_validation/cosmo_inference/data/glass_mocks/{chain_version}/\"\n", + "\n", + "# Choose the best-fit method\n", + "best_fit_method = \"2Dkde\"\n", + "\n", + "# Create the list of mocks\n", + "max_sim = 350\n", + "failed_simulations = [83]\n", + "roots = [f\"glass_mock_{chain_version}_{str(i).zfill(5)}\" for i in range(1, max_sim + 1)]\n", + "roots = [root for root in roots if int(root.split('_')[-1]) not in failed_simulations]\n", + "\n", + "catalog_versions = [\n", + " f'SP_v1.4.6.3_config/SP_v1.4.6.3_A',\n", + "]\n", + "\n", + "output_folder_chains = '/n23data1/n06data/lgoh/scratch/temp/' \n", + "path_ini_files = '/home/guerrini/sp_validation/cosmo_inference/cosmosis_config/'\n", + "output_fig_path = f\"/n23data1/n06data/lgoh/scratch/UNIONS/cosmo_inference/notebooks/Plots/\"\n", + "\n", + "ini_root =f'blind_A/fiducial'\n", + "\n", + "lower_bound_xi = 12\n", + "upper_bound_xi = 83" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Retrieve the chains" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#READ CHAIN\n", + "\n", + "chains=[]\n", + "best_fit = {}\n", + "\n", + "for i, root in enumerate(roots):\n", + " burnin = 0\n", + " \n", + " if os.path.isfile(f'{root_dir}/{root}/{root}/getdist_{root}.txt')==True:\n", + " \n", + " chain = g.samples_for_root(f'{root_dir}/{root}/{root}/getdist_{root}',\n", + " cache=False,\n", + " settings={'ignore_rows': burnin,\n", + " 'smooth_scale_2D':0.5,\n", + " 'smooth_scale_1D':0.5\n", + " })\n", + " p = chain.getParams()\n", + " \n", + " best_fit[root] = chain_postprocessing.extract_best_fit_params(chain, best_fit_method='2Dkde')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "param_list = ['OMEGA_M','ombh2','h0','n_s','SIGMA_8','s_8_input', 'logt_agn','a','m1','bias_1','alpha','beta', 'omch2', 'm', 'a_planck']\n", + "label_list = ['\\Omega_m', '\\omega_b', 'h_0', 'n_s', '\\sigma_8', 'S_8', 'log T_{AGN}', 'A_{IA}', 'm_1', '\\Delta z_1', '\\\\alpha_{PSF}', '\\\\beta_{PSF}', '\\omega_c', 'M', 'A_{\\rm Planck}']\n", + " " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Run `Cosmosis` in test mode to get the data vectors" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "if not os.path.exists(path_ini_files+'/values_empty.ini'):\n", + " content = \"\"\"[cosmological_parameters]\n", + "\n", + "tau = 0.0544\n", + "w = -1.0\n", + "mnu = 0.06\n", + "omega_k = 0.0\n", + "wa = 0.0\n", + "\n", + "[halo_model_parameters]\n", + "\n", + "[intrinsic_alignment_parameters]\n", + "\n", + "[shear_calibration_parameters]\n", + "\n", + "[nofz_shifts]\n", + "\n", + "[psf_leakage_parameters]\n", + "\"\"\"\n", + "\n", + " with open(path_ini_files+'/values_empty.ini', 'w') as f:\n", + " f.write(content)\n", + " f.close()\n", + "\n", + " print('File created successfully')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "section_map = {\n", + " 'omch2': 'cosmological_parameters',\n", + " 'ombh2': 'cosmological_parameters',\n", + " 'h0': 'cosmological_parameters',\n", + " 'n_s': 'cosmological_parameters',\n", + " 's_8_input': 'cosmological_parameters',\n", + " 'logt_agn': 'halo_model_parameters',\n", + " 'a': 'intrinsic_alignment_parameters',\n", + " 'm1': 'shear_calibration_parameters',\n", + " 'bias_1': 'nofz_shifts',\n", + " 'alpha': 'psf_leakage_parameters',\n", + " 'beta': 'psf_leakage_parameters',\n", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "env = os.environ.copy()\n", + "env[\"LD_LIBRARY_PATH\"] = \"/home/guerrini/.conda/envs/sp_validation/lib/python3.9/site-packages/cosmosis/datablock:\" + env.get(\"LD_LIBRARY_PATH\", \"\")\n", + "for i,root in enumerate(roots):\n", + " print(root)\n", + " config = configparser.ConfigParser()\n", + " config.optionxform = str # Preserve case sensitivity of option names\n", + "\n", + " for param, section in section_map.items():\n", + " # Check if this parameter exists for the current root\n", + " if param in best_fit[root]:\n", + " value = best_fit[root][param]\n", + " \n", + " if section not in config:\n", + " config.add_section(section)\n", + "\n", + " config[section][param] = str(value)\n", + "\n", + " with open(path_ini_files+'/values_empty.ini', 'w') as configfile:\n", + " config.write(configfile)\n", + "\n", + " #Modify the ini file to run in test mode at the best fit\n", + " config = configparser.ConfigParser()\n", + " config.optionxform = str # Preserve case sensitivity of option names\n", + " \n", + " ini_file = path_ini_files+f'config_space_v1.4.6.3_fiducial/pipeline/{ini_root}.ini'\n", + " config.read(ini_file)\n", + "\n", + " sampler = config['runtime']['sampler']\n", + " config['runtime']['sampler'] = 'test'\n", + " values = config['pipeline']['values']\n", + " config['pipeline']['values'] = path_ini_files + '/values_empty.ini'\n", + " config['DEFAULT']['FITS_FILE'] = f'{root_glass_dv}/glass_mock_{root[-5:]}/cosmosis_glass_mock_v6_{root[-5:]}.fits'\n", + " config['test']['save_dir'] = output_folder_chains + f'{root}/best_fit_config'\n", + " \n", + " with open(ini_file, 'w') as configfile:\n", + " config.write(configfile)\n", + "\n", + " #Run cosmosis\n", + " result = subprocess.run(\n", + " ['cosmosis', ini_file],\n", + " env=env,\n", + " capture_output=True,\n", + " text=True\n", + " )\n", + " # print(f\"STDOUT:\\n{result.stdout}\")\n", + " # print(f\"STDERR:\\n{result.stderr}\")\n", + "\n", + " #Modify the ini file to the previous one\n", + " config['pipeline']['values'] = values\n", + " config['runtime']['sampler'] = sampler\n", + "\n", + " with open(ini_file, 'w') as configfile:\n", + " config.write(configfile)\n", + " \n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "\n", + "xi_plus_chi2s = np.array([])\n", + "xi_minus_chi2s = np.array([])\n", + "xi_chi2s = np.array([])\n", + "tau_chi2s = np.array([])\n", + "chi2_tots = np.array([])\n", + "\n", + "\n", + "for idx,root in enumerate(roots):\n", + " print(root)\n", + "\n", + " data = fits.open(f'{root_glass_dv}/glass_mock_{root[-5:]}/cosmosis_glass_mock_v6_{root[-5:]}.fits')\n", + " \n", + " tau_0_data = data['TAU_0_PLUS'].data['VALUE']\n", + " tau_2_data = data['TAU_2_PLUS'].data['VALUE']\n", + "\n", + " theta_data = data['XI_PLUS'].data['ANG']\n", + " xi_plus_data = data['XI_PLUS'].data['VALUE']\n", + " xi_minus_data = data['XI_MINUS'].data['VALUE']\n", + " xi_data = np.concatenate((xi_plus_data, xi_minus_data))\n", + "\n", + " tau_data = np.concatenate((tau_0_data, tau_2_data))\n", + "\n", + " #Apply scale cuts\n", + " mask_xi_plus = (theta_data > lower_bound_xi) & (theta_data < upper_bound_xi)\n", + " mask_xi_minus = (theta_data > lower_bound_xi) & (theta_data < upper_bound_xi)\n", + " mask = np.concatenate((mask_xi_plus, mask_xi_minus))\n", + " #Load the covariance\n", + " cov = data['COVMAT'].data\n", + " cov_xi = cov[0:2*len(xi_plus_data), 0:2*len(xi_plus_data)]\n", + " cov_tau = cov[2*len(xi_plus_data):4*len(xi_plus_data), 2*len(xi_plus_data):4*len(xi_plus_data)]\n", + " xi_data = xi_data[mask]\n", + " cov_xi = cov_xi[mask][:, mask]\n", + "\n", + " cov_xi_plus = cov[0:len(xi_plus_data), 0:len(xi_plus_data)]\n", + " cov_xi_plus = cov_xi_plus[mask_xi_plus][:, mask_xi_plus]\n", + " cov_xi_minus = cov[len(xi_plus_data):2*len(xi_minus_data), len(xi_plus_data):2*len(xi_minus_data)]\n", + " cov_xi_minus = cov_xi_minus[mask_xi_minus][:, mask_xi_minus]\n", + "\n", + " #Read the results\n", + " theta = np.loadtxt(output_folder_chains + f'{root}/best_fit_config/shear_xi_plus/theta.txt')\n", + " theta_arcmin = theta * 180 * 60 / np.pi\n", + " shear_xi_plus = np.loadtxt(output_folder_chains + f'{root}/best_fit_config/shear_xi_plus/bin_1_1.txt')\n", + " shear_xi_minus = np.loadtxt(output_folder_chains + f'{root}/best_fit_config/shear_xi_minus/bin_1_1.txt')\n", + "\n", + " xi_sys_plus = np.loadtxt(output_folder_chains + f'{root}/best_fit_config/xi_sys/shear_xi_plus.txt')\n", + " xi_sys_minus = np.loadtxt(output_folder_chains + f'{root}/best_fit_config/xi_sys/shear_xi_minus.txt')\n", + "\n", + " theta_tau = np.loadtxt(output_folder_chains + f'{root}/best_fit_config/tau_0_plus/theta.txt')\n", + " theta_tau_arcmin = theta_tau * 180 * 60 / np.pi\n", + " tau_0_model = np.loadtxt(output_folder_chains + f'{root}/best_fit_config/tau_0_plus/bin_1_1.txt')\n", + " tau_2_model = np.loadtxt(output_folder_chains + f'{root}/best_fit_config/tau_2_plus/bin_1_1.txt')\n", + "\n", + " #interpolate the model\n", + " interp_xi_plus = interp1d(theta_arcmin, shear_xi_plus, kind='cubic', fill_value='extrapolate')\n", + " interp_xi_minus = interp1d(theta_arcmin, shear_xi_minus, kind='cubic', fill_value='extrapolate')\n", + "\n", + " xi_plus_model = interp_xi_plus(theta_data)\n", + " xi_plus_model += xi_sys_plus\n", + " xi_minus_model = interp_xi_minus(theta_data)\n", + " xi_minus_model += xi_sys_minus\n", + " \n", + " xi_model = np.concatenate((xi_plus_model, xi_minus_model))\n", + " tau_model = np.concatenate((tau_0_model, tau_2_model))\n", + " xi_model = xi_model[mask]\n", + "\n", + "\n", + " xi_plus_chi2 = np.dot((xi_plus_model[mask_xi_plus] - xi_plus_data[mask_xi_plus]), np.dot(np.linalg.inv(cov_xi_plus), (xi_plus_model[mask_xi_plus] - xi_plus_data[mask_xi_plus])))\n", + " xi_minus_chi2 = np.dot((xi_minus_model[mask_xi_minus] - xi_minus_data[mask_xi_minus]), np.dot(np.linalg.inv(cov_xi_minus), (xi_minus_model[mask_xi_minus] - xi_minus_data[mask_xi_minus])))\n", + " xi_chi2 = np.dot((xi_model - xi_data), np.dot(np.linalg.inv(cov_xi), (xi_model - xi_data)))\n", + " tau_chi2 = np.dot((tau_model - tau_data), np.dot(np.linalg.inv(cov_tau), (tau_model - tau_data)))\n", + " chi2_tot = xi_plus_chi2 + xi_minus_chi2 + tau_chi2\n", + "\n", + " xi_plus_chi2s = np.append(xi_plus_chi2s, xi_plus_chi2)\n", + " xi_minus_chi2s = np.append(xi_minus_chi2s, xi_minus_chi2)\n", + " xi_chi2s = np.append(xi_chi2s, xi_chi2)\n", + " tau_chi2s = np.append(tau_chi2s, tau_chi2)\n", + " chi2_tots = np.append(chi2_tots, chi2_tot)\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "\n", + "chi2_fiducial = -2*-37.924821474732546\n", + "dof, loc, scale = chi2.fit(chi2_tots, floc=0)\n", + "\n", + "print(f\"Best-fit dof: {dof:.2f}\")\n", + "counts, bin_edges = np.histogram(\n", + " chi2_tots,\n", + " bins=25,\n", + " density=True\n", + ")\n", + "\n", + "sns.histplot(\n", + " chi2_tots,\n", + " kde=False,\n", + " bins=bin_edges,\n", + " stat='density',\n", + " label=r\"$\\chi^2$ for \\texttt{GLASS} mocks best-fits\",\n", + " color='blue',\n", + " alpha=0.3\n", + ")\n", + "\n", + "# Compute the p-value\n", + "\n", + "# 1. Get in which bin the chi2 of the fiducial falls\n", + "bin_index = np.digitize(chi2_fiducial, bin_edges)\n", + "\n", + "# 2. Compute the p-value as the integral of the tail of the histogram\n", + "p_value = np.sum(counts[bin_index:]) * np.diff(bin_edges)[0]\n", + "\n", + "print(f\"P-value: {p_value}\")\n", + "\n", + "plt.axvline(chi2_fiducial, color='red', label=r'$\\chi^2$ of the fiducial')\n", + "\n", + "mantissa, exponent = np.frexp(p_value)\n", + "pte_string = rf\"${{\\rm PTE}} = {p_value:.4f}$\"\n", + "\n", + "x_text = 70\n", + "y_text = max(counts) * 0.95\n", + "plt.text(x_text, y_text, pte_string, fontsize=15, bbox=dict(facecolor='wheat', alpha=0.8, edgecolor='black'))\n", + "\n", + "chi2_string = rf\"${{\\rm Eff. dof}}= {dof:.1f}$\"\n", + "y_text = max(counts) * 0.85\n", + "plt.text(\n", + " x_text,\n", + " y_text,\n", + " chi2_string,\n", + " fontsize=15,\n", + " bbox=dict(facecolor='wheat', alpha=0.8, edgecolor='black')\n", + ")\n", + "\n", + "plt.xlabel(r\"$\\chi^2$\")\n", + "plt.ylabel(\"Density\")\n", + "plt.savefig(f\"{output_fig_path}/chi2_glass_mocks_p_value.pdf\")\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "fig, [ax1, ax2] = plt.subplots(2, 1, figsize=(7, 10))\n", + "chi2_fiducial = 10.21\n", + "dof, loc, scale = chi2.fit(xi_chi2s, floc=0)\n", + "\n", + "print(f\"Best-fit dof: {dof:.2f}\")\n", + "counts, bin_edges = np.histogram(\n", + " xi_chi2s,\n", + " bins=25,\n", + " density=True\n", + ")\n", + "\n", + "sns.histplot(\n", + " xi_chi2s,\n", + " ax=ax1,\n", + " kde=False,\n", + " bins=bin_edges,\n", + " stat='density',\n", + " label=r\"$\\chi^2$ for \\texttt{GLASS} mocks best-fits\",\n", + " color='green',\n", + " alpha=0.3\n", + ")\n", + "\n", + "# Compute the p-value\n", + "\n", + "# 1. Get in which bin the chi2 of the fiducial falls\n", + "bin_index = np.digitize(chi2_fiducial, bin_edges)\n", + "\n", + "# 2. Compute the p-value as the integral of the tail of the histogram\n", + "p_value = np.sum(counts[bin_index:]) * np.diff(bin_edges)[0]\n", + "\n", + "print(f\"P-value: {p_value}\")\n", + "\n", + "ax1.axvline(chi2_fiducial, color='red', label=r'$\\chi^2$ of the fiducial')\n", + "\n", + "mantissa, exponent = np.frexp(p_value)\n", + "pte_string = rf\"${{\\rm PTE}} = {p_value:.2f}$\"\n", + "print(f\"mantissa: {mantissa}, exponent: {exponent}\")\n", + "x_text = 15\n", + "y_text = max(counts) * 0.95\n", + "ax1.text(x_text, y_text, pte_string, fontsize=15, bbox=dict(facecolor='wheat', alpha=0.8, edgecolor='black'))\n", + "\n", + "chi2_string = rf\"${{\\rm Eff. dof}}= {dof:.1f}$\"\n", + "y_text = max(counts) * 0.85\n", + "ax1.text(\n", + " x_text,\n", + " y_text,\n", + " chi2_string,\n", + " fontsize=15,\n", + " bbox=dict(facecolor='wheat', alpha=0.8, edgecolor='black')\n", + ")\n", + "\n", + "ax1.set_xlabel(r\"$\\chi^2 (\\xi_\\pm)$\")\n", + "ax1.set_ylabel(\"Density\")\n", + "\n", + "chi2_fiducial = 65.78\n", + "dof, loc, scale = chi2.fit(tau_chi2s, floc=0)\n", + "\n", + "print(f\"Best-fit dof: {dof:.2f}\")\n", + "counts, bin_edges = np.histogram(\n", + " tau_chi2s,\n", + " bins=25,\n", + " density=True\n", + ")\n", + "\n", + "sns.histplot(\n", + " tau_chi2s,\n", + " ax=ax2,\n", + "\n", + " kde=False,\n", + " bins=bin_edges,\n", + " stat='density',\n", + " label=r\"$\\chi^2$ for \\texttt{GLASS} mocks best-fits\",\n", + " color='pink',\n", + " alpha=0.5\n", + ")\n", + "\n", + "# Compute the p-value\n", + "\n", + "# 1. Get in which bin the chi2 of the fiducial falls\n", + "bin_index = np.digitize(chi2_fiducial, bin_edges)\n", + "\n", + "# 2. Compute the p-value as the integral of the tail of the histogram\n", + "p_value = np.sum(counts[bin_index:]) * np.diff(bin_edges)[0]\n", + "\n", + "print(f\"P-value: {p_value}\")\n", + "\n", + "ax2.axvline(chi2_fiducial, color='red', label=r'$\\chi^2$ of the fiducial')\n", + "\n", + "mantissa, exponent = np.frexp(p_value)\n", + "print(f\"mantissa: {mantissa}, exponent: {exponent}\")\n", + "pte_string = rf\"${{\\rm PTE}} = {p_value:.4f}$\"\n", + "# rf\"${{\\rm PTE}} = {mantissa:.2f} \\times 10^{{{exponent}}}$\" if exponent != 0 else \n", + "x_text = 60\n", + "y_text = max(counts) * 0.95\n", + "ax2.text(x_text, y_text, pte_string, fontsize=15, bbox=dict(facecolor='wheat', alpha=0.8, edgecolor='black'))\n", + "\n", + "chi2_string = rf\"${{\\rm Eff. dof}}= {dof:.1f}$\"\n", + "y_text = max(counts) * 0.85\n", + "ax2.text(\n", + " x_text,\n", + " y_text,\n", + " chi2_string,\n", + " fontsize=15,\n", + " bbox=dict(facecolor='wheat', alpha=0.8, edgecolor='black')\n", + ")\n", + "\n", + "ax2.set_xlabel(r\"$\\chi^2 (\\tau_{0,2})$\")\n", + "ax2.set_ylabel(\"Density\")\n", + "fig.savefig(f\"{output_fig_path}/chi2_glass_mocks_p_value_xi_tau.pdf\")\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "my_env", + "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.10.13" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/cosmo_inference/notebooks/2D_cosmic_shear_configuration_plots/get_prior_psf_leakage.ipynb b/cosmo_inference/notebooks/2D_cosmic_shear_configuration_plots/get_prior_psf_leakage.ipynb new file mode 100644 index 00000000..2381654c --- /dev/null +++ b/cosmo_inference/notebooks/2D_cosmic_shear_configuration_plots/get_prior_psf_leakage.ipynb @@ -0,0 +1,249 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "2978bafe", + "metadata": {}, + "source": [ + "# Covariance matrix and PSF leakage\n", + "\n", + "This notebook plots the combined covariance matrix, and samples and plots the 2D marginalised posteriors of the PSF leakage parameters $\\alpha$ and $\\beta$." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "54601eff", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "if not os.path.exists(\"./Plots\"):\n", + " os.makedirs(\"./Plots\")\n", + "\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "from astropy.io import fits\n", + "import seaborn as sns\n", + "from getdist import plots, loadMCSamples, MCSamples\n", + "\n", + "from shear_psf_leakage.rho_tau_stat import RhoStat, TauStat, PSFErrorFit\n", + "\n", + "# Use paper style and seaborn with husl palette\n", + "plt.style.use(\n", + " \"/home/guerrini/matplotlib_config/paper.mplstyle\"\n", + ")\n", + "# Set default palette - will be updated per plot as needed\n", + "sns.set_palette(\"husl\")\n", + "%matplotlib inline\n", + "\n", + "g = plots.get_subplot_plotter(width_inch=30)\n", + "g.settings.axes_fontsize=30\n", + "g.settings.axes_labelsize=30\n", + "g.settings.alpha_filled_add = 0.7\n", + "g.settings.legend_fontsize = 25\n", + "\n", + "ver = 'v1.4.6.3'\n", + "blind = 'B'" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4a1618a7", + "metadata": {}, + "outputs": [], + "source": [ + "data_path = f\"/home/guerrini/sp_validation/cosmo_inference/data/SP_{ver}_config/\"\n", + "\n", + "path_cosmo_val = \"/home/guerrini/sp_validation/notebooks/cosmo_val/output/\"\n", + "\n", + "roots = [\n", + " f\"SP_{ver}_{blind}\",\n", + " f\"SP_{ver}_leak_corr_{blind}\"\n", + "]\n", + "\n", + "labels = [\n", + " f\"SP_{ver}_{blind}\",\n", + " f\"SP_{ver}_leak_corr_{blind}\"\n", + "]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6c8c0a1f", + "metadata": {}, + "outputs": [], + "source": [ + "data_vectors = []\n", + "\n", + "for root in roots:\n", + " data_vectors.append(\n", + " fits.open(data_path +f\"SP_{ver}_{blind}/cosmosis_{root}_masked.fits\")\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "af22339d", + "metadata": {}, + "outputs": [], + "source": [ + "def cov_to_corr(cov):\n", + " \"\"\"Convert a covariance matrix to a correlation matrix.\"\"\"\n", + " d = np.sqrt(np.diag(cov))\n", + " corr = cov / np.outer(d, d)\n", + " corr[cov == 0] = 0\n", + " return corr" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a5d8de0d", + "metadata": {}, + "outputs": [], + "source": [ + "#Print the covariance matrix for each root\n", + "for i, root in enumerate(roots):\n", + " print(f\"Covariance matrix for {labels[i]}:\")\n", + " cov = data_vectors[i][\"COVMAT\"].data\n", + "\n", + " n_bins = cov.shape[0] // 4\n", + "\n", + " fig, ax = plt.subplots(figsize=(10, 8))\n", + "\n", + " im = ax.imshow(cov_to_corr(cov), vmin=-1, vmax=1, cmap=\"seismic\")\n", + " ax.set_aspect('equal')\n", + " ax.set_yticks(np.array([10, 30, 50, 70]))\n", + " ax.set_yticklabels([r\"$\\xi_+(\\vartheta)$\", r\"$\\xi_-(\\vartheta)$\", r\"$\\tau_0(\\vartheta)$\", r\"$\\tau_2(\\vartheta)$\"])\n", + " ax.set_xticks(np.array([10, 30, 50, 70]))\n", + " ax.set_xticklabels([r\"$\\xi_+(\\vartheta)$\", r\"$\\xi_-(\\vartheta)$\", r\"$\\tau_0(\\vartheta)$\", r\"$\\tau_2(\\vartheta)$\"], rotation=45)\n", + " fig.colorbar(im, ax=ax)\n", + "\n", + " plt.savefig(f\"./Plots/cov_matrix_{root}.png\", bbox_inches='tight', dpi=300)\n", + " plt.show()\n", + " print(\"\\n\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a484afb6", + "metadata": {}, + "outputs": [], + "source": [ + "#Create dummy rho and tau stat handler.\n", + "\n", + "#Inference of the xi_sys parameters\n", + "sep_units = 'arcmin'\n", + "coord_units = 'degrees'\n", + "theta_min = 1.0\n", + "theta_max = 250\n", + "nbins = 20\n", + "\n", + "\n", + "TreeCorrConfig_xi = {\n", + " 'ra_units': coord_units,\n", + " 'dec_units': coord_units,\n", + " 'min_sep': theta_min,\n", + " 'max_sep': theta_max,\n", + " 'sep_units': sep_units,\n", + " 'nbins': nbins,\n", + " 'var_method':'jackknife',\n", + "}\n", + "\n", + "rho_stats_handler = RhoStat(\n", + " output='.',\n", + " treecorr_config=TreeCorrConfig_xi,\n", + " verbose=True\n", + ")\n", + "\n", + "tau_stats_handler = TauStat(\n", + " catalogs=rho_stats_handler.catalogs,\n", + " output='.',\n", + " treecorr_config=TreeCorrConfig_xi,\n", + " verbose=True\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a4dd4416", + "metadata": {}, + "outputs": [], + "source": [ + "#Create a PSFErrorFit instance\n", + "psf_fitter = PSFErrorFit(rho_stats_handler, tau_stats_handler, path_cosmo_val+'rho_tau_stats/', use_eta=False)\n", + "\n", + "g = plots.get_subplot_plotter(width_inch=30)\n", + "\n", + "g.settings.axes_fontsize=30\n", + "g.settings.axes_labelsize=30\n", + "g.settings.alpha_filled_add = 0.7\n", + "g.settings.legend_fontsize = 40\n", + "\n", + "chains = []\n", + "\n", + "#Load rho-, tau-statistics, and cov_tau from the data_vector\n", + "for i, root in enumerate(roots):\n", + " print(\"Sampling PSF parameters for \", labels[i])\n", + " path_rho = f\"rho_stats_{root}.fits\"\n", + " path_tau = f\"tau_stats_{root}.fits\"\n", + " path_cov_rho = f\"cov_rho_{root}.npy\"\n", + " path_cov_tau = f\"cov_tau_{root}_th.npy\"\n", + " psf_fitter.load_rho_stat(path_rho)\n", + " psf_fitter.load_tau_stat(path_tau)\n", + " psf_fitter.load_covariance(path_cov_rho, cov_type='rho')\n", + " psf_fitter.load_covariance(path_cov_tau, cov_type='tau')\n", + " samples_lq, _, _ = psf_fitter.get_least_squares_params_samples(npatch=None, apply_debias=False)\n", + "\n", + " samples_gd = MCSamples(samples=samples_lq, names=[r\"\\alpha\", r\"\\beta\"], labels=[r\"\\alpha\", r\"\\beta\"])\n", + "\n", + " chains.append(samples_gd)\n", + "\n", + "g.triangle_plot(chains,\n", + " filled=True,\n", + " legend_labels=labels,\n", + " legend_loc='upper right',\n", + " \n", + ")\n", + "\n", + "# plt.savefig(f\"./Plots/psf_leakage_params.png\", bbox_inches='tight', dpi=300)\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a24f3510", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "my_env", + "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.10.13" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/cosmo_inference/notebooks/2D_cosmic_shear_configuration_plots/glass_mock_hist.ipynb b/cosmo_inference/notebooks/2D_cosmic_shear_configuration_plots/glass_mock_hist.ipynb new file mode 100644 index 00000000..23aecd9f --- /dev/null +++ b/cosmo_inference/notebooks/2D_cosmic_shear_configuration_plots/glass_mock_hist.ipynb @@ -0,0 +1,486 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "255d7eca", + "metadata": { + "lines_to_next_cell": 2 + }, + "outputs": [], + "source": [ + "import IPython\n", + "\n", + "ipython = IPython.get_ipython()\n", + "\n", + "if ipython is not None:\n", + " ipython.run_line_magic('load_ext', 'autoreload')\n", + " ipython.run_line_magic('autoreload', '2')\n", + "\n", + "import os\n", + "import copy\n", + "from tqdm import tqdm\n", + "\n", + "import matplotlib.pyplot as plt\n", + "from mpl_toolkits.axes_grid1 import make_axes_locatable\n", + "import numpy as np\n", + "import healpy as hp\n", + "import seaborn as sns\n", + "from astropy.io import fits\n", + "\n", + "from getdist import plots, MCSamples\n", + "\n", + "g = plots.get_subplot_plotter(width_inch=7)\n", + "g.settings.axes_fontsize=15\n", + "g.settings.axes_labelsize=15\n", + "g.settings.alpha_filled_add = 0.7\n", + "g.settings.legend_fontsize = 15\n", + "\n", + "if os.path.exists(\"/home/guerrini/matplotlib_config/paper.mplstyle\"):\n", + " plt.style.use(\n", + " \"/home/guerrini/matplotlib_config/paper.mplstyle\"\n", + " )\n", + "\n", + "# Set default palette - will be updated per plot as needed\n", + "sns.set_palette(\"husl\")\n", + "\n", + "if ipython is not None:\n", + " ipython.run_line_magic('matplotlib', 'inline')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bd3492f5", + "metadata": { + "lines_to_next_cell": 1 + }, + "outputs": [], + "source": [ + "root_dir = '/n09data/guerrini/glass_mock_chains/'\n", + "chain_version = 'v6'\n", + "num_sims = 350\n", + "\n", + "roots = [\n", + " f\"glass_mock_{chain_version}_{i+1:05d}\" for i in range(num_sims)\n", + "]\n", + "\n", + "\n", + "# # %%\n", + "def load_samples_and_write_paramames(root_dir, root, chain_type=\"configuration\"):\n", + " assert chain_type in [\"configuration\", \"harmonic\"], \"chain_type must be 'configuration' or 'harmonic'\"\n", + "\n", + " if chain_type == \"configuration\":\n", + " path_samples = root_dir + '{}/{}/samples_{}.txt'.format('/'+root, root, root)\n", + " path_paramnames = root_dir + '{}/{}/getdist_{}.paramnames'.format('/'+root, root, root)\n", + " else:\n", + " path_samples = root_dir + '{}/{}/samples_{}_cell.txt'.format('/'+root, root, root)\n", + " path_paramnames = root_dir + '{}/{}/getdist_{}_cell.paramnames'.format('/'+root, root, root)\n", + " \n", + " with open(path_samples, 'r') as file:\n", + " params = file.readline()[1:].split('\\t')[:-4]\n", + " file.close()\n", + "\n", + " with open(path_paramnames, 'w') as file:\n", + " for i in range(len(params)):\n", + " if len(params[i].split('--')) > 1:\n", + " file.write(params[i].split('--')[1] + '\\n')\n", + " else:\n", + " file.write(params[i].split('--')[0] + '\\n')\n", + " file.close()\n", + "\n", + "def write_samples_getdist_format(root_dir, root, chain_type=\"configuration\"):\n", + " assert chain_type in [\"configuration\", \"harmonic\"], \"chain_type must be 'configuration' or 'harmonic'\"\n", + "\n", + " if chain_type == \"configuration\":\n", + " path_samples = root_dir + '{}/{}/samples_{}.txt'.format('/'+root, root, root)\n", + " path_gd_samples = root_dir + '{}/{}/getdist_{}.txt'.format('/'+root, root, root)\n", + " path_gd = root_dir + '{}/{}/getdist_{}'.format(root,root,root)\n", + " else:\n", + " path_samples = root_dir + '{}/{}/samples_{}_cell.txt'.format('/'+root, root, root)\n", + " path_gd_samples = root_dir + '{}/{}/getdist_{}_cell.txt'.format('/'+root, root, root)\n", + " path_gd = root_dir + '{}/{}/getdist_{}_cell'.format(root,root,root)\n", + " \n", + " samples = np.loadtxt(\n", + " path_samples,\n", + " )\n", + " if 'nautilus' in root:\n", + " samples = np.column_stack((np.exp(samples[:,-3]),samples[:,-1]-samples[:,-2],samples[:,0:-3]))\n", + " else:\n", + " samples = np.column_stack((samples[:,-1],samples[:,-2],samples[:,0:-4]))\n", + " np.savetxt(path_gd_samples, samples)\n", + "\n", + " chain = g.samples_for_root(\n", + " path_gd,\n", + " cache=False,\n", + " settings={\n", + " 'ignore_rows': 0.,\n", + " 'smooth_scale_2D': 0.5,\n", + " 'smooth_scale_1D': 0.5\n", + " }\n", + " )\n", + "\n", + " return chain\n", + "\n", + "def extract_param_chain(chain, param_names):\n", + " margestats = chain.getMargeStats()\n", + " likestats = chain.getLikeStats()\n", + "\n", + " param_values = {}\n", + " for param_name in param_names:\n", + " if param_name not in chain.getParamNames().list():\n", + " raise ValueError(f\"Parameter {param_name} not found in chain.\")\n", + " \n", + " param_stats = margestats.parWithName(param_name)\n", + " param_values[param_name] = {\n", + " 'mean': param_stats.mean,\n", + " '1sigma_minus': param_stats.mean - param_stats.limits[0].lower,\n", + " '1sigma_plus': param_stats.limits[0].upper - param_stats.mean,\n", + " '2sigma_minus': param_stats.mean - param_stats.limits[1].lower,\n", + " '2sigma_plus': param_stats.limits[1].upper - param_stats.mean,\n", + " }\n", + "\n", + " param_stats = likestats.parWithName(param_name)\n", + " param_names_getdist = chain.getParamNames()\n", + " par = param_names_getdist.parWithName(param_name)\n", + " kde = chain.get1DDensity(par, num_bins=1000)\n", + " kde_map = kde.x[np.argmax(kde.P)]\n", + " param_values[param_name].update({\n", + " 'MAP': kde_map,\n", + " })\n", + " \n", + " par = chain.getParamNames().parWithName(\"S_8\")\n", + " par_om = chain.getParamNames().parWithName(\"OMEGA_M\")\n", + " kde = chain.get2DDensity(par, par_om, fine_bins_2D=1000)\n", + " s8_kde_map = kde.x[np.unravel_index(np.argmax(kde.P), kde.P.shape)[1]]\n", + " om_kde_map = kde.y[np.unravel_index(np.argmax(kde.P), kde.P.shape)[0]]\n", + " param_values[\"S_8\"].update({\n", + " 'MAP_2D': s8_kde_map,\n", + " })\n", + " param_values[\"OMEGA_M\"].update({\n", + " 'MAP_2D': om_kde_map,\n", + " })\n", + "\n", + " return param_values\n", + "\n", + "def concatenate_param_stats(name, param_values, verbose=False):\n", + " output = [name]\n", + " for key in param_values.keys():\n", + " param_stat = param_values[key]\n", + " if verbose:\n", + " print(f\"{name} - {key}: {param_stat['mean']:.4f} +{param_stat['1sigma_plus']:.4f}/-{param_stat['1sigma_minus']:.4f} (1σ), +{param_stat['2sigma_plus']:.4f}/-{param_stat['2sigma_minus']:.4f} (2σ)\")\n", + "\n", + " param_list = [\n", + " param_stat['mean'],\n", + " param_stat['1sigma_minus'],\n", + " param_stat['1sigma_plus'],\n", + " param_stat['2sigma_minus'],\n", + " param_stat['2sigma_plus'],\n", + " param_stat['MAP']\n", + " ]\n", + "\n", + " if key == \"S_8\":\n", + " param_list.append(param_stat['MAP_2D'])\n", + " \n", + " if key == \"OMEGA_M\":\n", + " param_list.append(param_stat['MAP_2D'])\n", + "\n", + " output += param_list\n", + "\n", + " return output\n", + "\n", + "def merge_param_stats(params_configuration, params_harmonic):\n", + " merged_params = {}\n", + " for key in params_configuration.keys():\n", + " if key in params_harmonic:\n", + " merged_params[key] = {\n", + " 'configuration': params_configuration[key],\n", + " 'harmonic': params_harmonic[key]\n", + " }\n", + " return merged_params\n", + "\n", + "def concatenate_merge_params(name, merged_params, verbose=False):\n", + " output = [name]\n", + " for key in merged_params.keys():\n", + " param_config = merged_params[key]['configuration']\n", + " param_harm = merged_params[key]['harmonic']\n", + "\n", + " if verbose:\n", + " print(f\"{name} - {key} (Configuration): {param_config['mean']:.4f} +{param_config['1sigma_plus']:.4f}/-{param_config['1sigma_minus']:.4f} (1σ), +{param_config['2sigma_plus']:.4f}/-{param_config['2sigma_minus']:.4f} (2σ)\")\n", + " print(f\"{name} - {key} (Harmonic): {param_harm['mean']:.4f} +{param_harm['1sigma_plus']:.4f}/-{param_harm['1sigma_minus']:.4f} (1σ), +{param_harm['2sigma_plus']:.4f}/-{param_harm['2sigma_minus']:.4f} (2σ)\")\n", + "\n", + " param_list = [\n", + " param_config['mean'],\n", + " param_config['1sigma_minus'],\n", + " param_config['1sigma_plus'],\n", + " param_config['2sigma_minus'],\n", + " param_config['2sigma_plus'],\n", + " param_config['MAP'],\n", + " param_harm['mean'],\n", + " param_harm['1sigma_minus'],\n", + " param_harm['1sigma_plus'],\n", + " param_harm['2sigma_minus'],\n", + " param_harm['2sigma_plus'],\n", + " param_harm['MAP']\n", + " ]\n", + "\n", + " output += param_list\n", + "\n", + " return output" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c3c3b0c8", + "metadata": { + "lines_to_next_cell": 0 + }, + "outputs": [], + "source": [ + "chain_harmonic = []\n", + "chain_config = []\n", + "\n", + "for i, root in enumerate(tqdm(roots)):\n", + " if os.path.isfile(f'{root_dir}/{root}/{root}/getdist_{root}.txt'):\n", + " # Load samples and write paramnames for harmonic space\n", + " load_samples_and_write_paramames(root_dir, root, chain_type=\"harmonic\")\n", + " write_samples_getdist_format(root_dir, root, chain_type=\"harmonic\")\n", + " chain_harm = g.samples_for_root(\n", + " root_dir + f'/{root}/{root}/getdist_{root}_cell',\n", + " cache=False,\n", + " settings={\n", + " 'ignore_rows': 0.,\n", + " 'smooth_scale_2D': 0.5,\n", + " 'smooth_scale_1D': 0.5\n", + " }\n", + " )\n", + " chain_harmonic.append(chain_harm)\n", + " \n", + " # Load samples and write paramnames for harmonic space\n", + " load_samples_and_write_paramames(root_dir, root, chain_type=\"configuration\")\n", + " write_samples_getdist_format(root_dir, root, chain_type=\"configuration\")\n", + " chain_conf = g.samples_for_root(\n", + " root_dir + f'/{root}/{root}/getdist_{root}',\n", + " cache=False,\n", + " settings={\n", + " 'ignore_rows': 0.,\n", + " 'smooth_scale_2D': 0.5,\n", + " 'smooth_scale_1D': 0.5\n", + " }\n", + " )\n", + " chain_config.append(chain_conf)\n", + "# # %%\n", + "param_names = ['S_8', 'OMEGA_M', 'SIGMA_8', 'a']\n", + "\n", + "output_mocks_harm = np.array([\n", + " \"Name\",\n", + " \"S8_mean\", \"S8_1sigma_minus\", \"S8_1sigma_plus\", \"S8_2sigma_minus\", \"S8_2sigma_plus\", \"S8_MAP\", \"S8_MAP_2D\",\n", + " \"OMEGA_M_mean\", \"OMEGA_M_1sigma_minus\", \"OMEGA_M_1sigma_plus\", \"OMEGA_M_2sigma_minus\", \"OMEGA_M_2sigma_plus\", \"OMEGA_M_MAP\", \"OMEGA_M_MAP_2D\",\n", + " \"SIGMA_8_mean\", \"SIGMA_8_1sigma_minus\", \"SIGMA_8_1sigma_plus\", \"SIGMA_8_2sigma_minus\", \"SIGMA_8_2sigma_plus\", \"SIGMA_8_MAP\",\n", + " \"a_mean\", \"a_1sigma_minus\", \"a_1sigma_plus\", \"a_2sigma_minus\", \"a_2sigma_plus\", \"a_MAP\"\n", + "])\n", + "\n", + "output_mocks_config = np.array([\n", + " \"Name\",\n", + " \"S8_mean\", \"S8_1sigma_minus\", \"S8_1sigma_plus\", \"S8_2sigma_minus\", \"S8_2sigma_plus\", \"S8_MAP\", \"S8_MAP_2D\",\n", + " \"OMEGA_M_mean\", \"OMEGA_M_1sigma_minus\", \"OMEGA_M_1sigma_plus\", \"OMEGA_M_2sigma_minus\", \"OMEGA_M_2sigma_plus\", \"OMEGA_M_MAP\", \"OMEGA_M_MAP_2D\",\n", + " \"SIGMA_8_mean\", \"SIGMA_8_1sigma_minus\", \"SIGMA_8_1sigma_plus\", \"SIGMA_8_2sigma_minus\", \"SIGMA_8_2sigma_plus\", \"SIGMA_8_MAP\",\n", + " \"a_mean\", \"a_1sigma_minus\", \"a_1sigma_plus\", \"a_2sigma_minus\", \"a_2sigma_plus\", \"a_MAP\"\n", + "])\n", + "\n", + "for i, root in enumerate(tqdm(roots[:-1])):\n", + " param_values_harm = extract_param_chain(chain_harmonic[i], param_names)\n", + "\n", + " param_harm = concatenate_param_stats(root, param_values_harm, verbose=False)\n", + " \n", + " output_mocks_harm = np.vstack((output_mocks_harm, param_harm))\n", + "\n", + " param_values_config = extract_param_chain(chain_config[i], param_names)\n", + "\n", + " param_config = concatenate_param_stats(root, param_values_config, verbose=False)\n", + " \n", + " output_mocks_config = np.vstack((output_mocks_config, param_config))\n", + "\n", + "np.savetxt(f\"summary_parameter_constraints_harmonic_space_{chain_version}.txt\", output_mocks_harm, fmt='%s', delimiter=';')\n", + "np.savetxt(f\"summary_parameter_constraints_configuration_space_{chain_version}.txt\", output_mocks_config, fmt='%s', delimiter=';')\n", + "print(f\"Saved summary of parameter constraints for harmonic space in summary_parameter_constraints_harmonic_space_{chain_version}.txt\")\n", + "print(f\"Saved summary of parameter constraints for configuration space in summary_parameter_constraints_configuration_space_{chain_version}.txt\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1fdccd58", + "metadata": { + "lines_to_next_cell": 0 + }, + "outputs": [], + "source": [ + "import pandas as pd\n", + "\n", + "output_df_harm = pd.read_csv(\n", + " f\"summary_parameter_constraints_harmonic_space_{chain_version}.txt\",\n", + " delimiter=';',\n", + " skiprows=1,\n", + " names=output_mocks_harm[0]\n", + ")\n", + "\n", + "output_df_config = pd.read_csv(\n", + " f\"summary_parameter_constraints_configuration_space_{chain_version}.txt\",\n", + " delimiter=';',\n", + " skiprows=1,\n", + " names=output_mocks_config[0]\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c8c31d9e", + "metadata": {}, + "outputs": [], + "source": [ + "# Define the true value of the parameters\n", + "from astropy.cosmology import Planck18 as planck\n", + "\n", + "Omega_m_fid = planck.Om0\n", + "sigma_8_fid = 0.8102\n", + "s8_fid = sigma_8_fid * (Omega_m_fid / 0.3)**0.5\n", + "h = planck.h\n", + "Omega_b_fig = planck.Ob0\n", + "n_s_fid = 0.9665\n", + "print(f\"Fiducial values: Omega_m = {Omega_m_fid}, sigma_8 = {sigma_8_fid}, S_8 = {s8_fid}\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e36dbc91", + "metadata": {}, + "outputs": [], + "source": [ + "sns.histplot(\n", + " output_df_harm[\"S8_mean\"]-output_df_config[\"S8_mean\"],\n", + " kde=True,\n", + " bins=30,\n", + " label=\"Mean\"\n", + ")\n", + "# sns.histplot(\n", + "# output_df_harm[\"S8_MAP\"]-output_df_config[\"S8_MAP\"],\n", + "# kde=True,\n", + "# bins=20,\n", + "# label=\"MAP\",\n", + "# )\n", + "sns.histplot(\n", + " output_df_harm[\"S8_MAP_2D\"]-output_df_config[\"S8_MAP_2D\"],\n", + " kde=True,\n", + " bins=30,\n", + " label=\"2D Mode\",\n", + " alpha=0.5\n", + ")\n", + "plt.axvline(0, color=\"black\", linestyle=\"--\")\n", + "plt.legend(fontsize=12)\n", + "\n", + "plt.xlabel(r\"$\\Delta S_8$\")\n", + "plt.savefig(\"/n23data1/n06data/lgoh/scratch/UNIONS/cosmo_inference/notebooks/Plots/S8_comparison_harmonic_vs_configuration.pdf\", bbox_inches='tight')\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d945adc3", + "metadata": {}, + "outputs": [], + "source": [ + "output_df_config[\"S8_MAP_2D\"].shape\n", + "output_df_harm[\"S8_MAP_2D\"].shape" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "41062616", + "metadata": { + "lines_to_next_cell": 2 + }, + "outputs": [], + "source": [ + "# Create JointGrid\n", + "g = sns.JointGrid(x=output_df_config['OMEGA_M_MAP_2D'], y=output_df_config['S8_MAP_2D'], height=7, ratio=5, space=0)\n", + "\n", + "# Main 2D histogram\n", + "sns.histplot(\n", + " x=output_df_config['OMEGA_M_MAP_2D'],\n", + " y=output_df_config['S8_MAP_2D'],\n", + " bins=25,\n", + " cmap=\"Greens\",\n", + " cbar=False,\n", + " ax=g.ax_joint\n", + ")\n", + "\n", + "# Marginal histograms\n", + "sns.histplot(x=output_df_config['OMEGA_M_MAP_2D'], bins=25, color=\"#2ca25f\", ax=g.ax_marg_x)\n", + "sns.histplot(y=output_df_config['S8_MAP_2D'], bins=25, color=\"#2ca25f\", ax=g.ax_marg_y)\n", + "\n", + "# Add dashed reference lines\n", + "g.ax_joint.axvline(Omega_m_fid, color='k', linestyle='--')\n", + "g.ax_joint.axhline(s8_fid, color='k', linestyle='--')\n", + "\n", + "# Labels\n", + "g.set_axis_labels(\n", + " r'$\\Omega_m$ estimated from mocks (Configuration space)',\n", + " r'$S_8$ estimated from mocks (Configuration space)'\n", + ")\n", + "\n", + "# Optional styling tweaks\n", + "g.ax_joint.tick_params(labelsize=12)\n", + "plt.savefig(\"/n23data1/n06data/lgoh/scratch/UNIONS/cosmo_inference/notebooks/Plots/S8_vs_OmegaM_configuration_space_mocks.pdf\", bbox_inches='tight')\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2cc18e1f", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9f530e3c", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "jupytext": { + "cell_metadata_filter": "-all", + "main_language": "python", + "notebook_metadata_filter": "-all" + }, + "kernelspec": { + "display_name": "my_env", + "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.10.13" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/cosmo_inference/notebooks/2D_cosmic_shear_configuration_plots/masking.ipynb b/cosmo_inference/notebooks/2D_cosmic_shear_configuration_plots/masking.ipynb new file mode 100644 index 00000000..d4b2ed97 --- /dev/null +++ b/cosmo_inference/notebooks/2D_cosmic_shear_configuration_plots/masking.ipynb @@ -0,0 +1,151 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Covmat mask analysis\n", + "\n", + "This notebook creates the plots to look at the ratio of the covaraiance matrices when applying the mask or not" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "\n", + "import os\n", + "import numpy as np\n", + "import healpy as hp\n", + "from astropy.io import fits\n", + "import matplotlib.pyplot as plt\n", + "import seaborn as sns\n", + "plt.style.use(\n", + " \"/home/guerrini/matplotlib_config/paper.mplstyle\"\n", + ")\n", + "\n", + "plt.rcParams['axes.labelsize'] = 18\n", + "plt.rcParams['xtick.labelsize'] = 18\n", + "plt.rcParams['ytick.labelsize'] = 18\n", + "\n", + "plt.rcParams['text.usetex'] = True\n", + "sns.set_palette(\"husl\")\n", + "\n", + "cat_dir = '/n17data/UNIONS/WL/v1.4.x/'\n", + "catalog_ver = 'v1.4.6.3'\n", + "blind = 'B'\n", + "\n", + "nside = 8192\n", + "npix = hp.nside2npix(nside)\n", + "\n", + "data_dir = f'/n23data1/n06data/lgoh/scratch/UNIONS/cosmo_inference/data/'\n", + "curr_dir = os.getcwd()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# PLOT 2D MAP OF COVMAT masked vs unmasked RATIOS\n", + "nbins=20\n", + "ndata = nbins * 2 \n", + "full_ratio = np.zeros((ndata,ndata))\n", + "\n", + "cov = np.loadtxt(data_dir + f'/covs/cov_SP_{catalog_ver}_{blind}.txt')\n", + "cov_masked = np.loadtxt(data_dir + f'/covs/cov_masked_SP_{catalog_ver}_{blind}.txt')\n", + "\n", + "for i in range(ndata):\n", + " for j in range(ndata):\n", + " full_ratio[i][j] = cov_masked[i][j] / cov[i][j]\n", + "\n", + "fig = plt.figure()\n", + "ax = fig.add_subplot(1, 1, 1) \n", + "extent = (0, ndata, ndata, 0)\n", + "\n", + "vmin, vmax = np.percentile(full_ratio, [1, 99])\n", + "\n", + "im3 = ax.imshow(full_ratio, cmap='RdBu_r', vmin=vmin, vmax=vmax, extent=extent)\n", + "\n", + "cbar = fig.colorbar(im3, ax=ax, fraction=0.046, pad=0.04)\n", + "\n", + "ax.text(int(ndata/4), ndata+5, r'$\\xi_+$', fontsize=15)\n", + "ax.text(3*int(ndata/4), ndata+5, r'$\\xi_-$', fontsize=15)\n", + "ax.text(-8, int(ndata/4), r'$\\xi_+$', fontsize=15, rotation=90)\n", + "ax.text(-8, 3*int(ndata/4), r'$\\xi_-$', fontsize=15,rotation=90)\n", + "ax.set_xticks([0,10,20,30,40])\n", + "ax.set_yticks([0,10,20,30,40])\n", + "ax.set_yticklabels([\"1'\", \"125'\", \"250'\", \"125'\", \"250'\"])\n", + "ax.set_xticklabels([\"1'\", \"125'\", \"250'\", \"125'\", \"250'\"])\n", + "plt.axvline(x=int(ndata/2), color='white', linewidth=1.0)\n", + "plt.axhline(y=int(ndata/2), color='white', linewidth=1.0)\n", + "\n", + "plt.savefig(f'{curr_dir}/../Plots/covmat_masked_unmasked_ratio_{catalog_ver}_{blind}.pdf', bbox_inches='tight')\n", + "plt.show()\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAm8AAAHPCAYAAAAFwj37AAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjgsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvwVt1zgAAAAlwSFlzAAAPYQAAD2EBqD+naQAAfi5JREFUeJzt3XlcU2e+P/DPOVlYFBLAXVEJ7kuVAHbfJNTpOlMF6XSWzsytUGe7y7RS5nfvndu7Ian33tlb0JnO1kVBO91HiXa6TlsgYNW6EnBfyQIqkO38/oikUkFZTnKS8Hm/XnkJyZPzfMkx4ctznuf7CJIkSSAiIiKiqCAqHQARERERDRyTNyIiIqIowuSNiIiIKIoweSMiIiKKIkzeiIiIiKIIkzciIiKiKMLkjYiIiCiKqJUOIJr5/X6cOHECSUlJEARB6XCIiIgoikmShI6ODkyaNAmi2P/4GpO3YThx4gTS09OVDoOIiIhiyNGjRzFlypR+H2fyNgxJSUkAAi9ycnKywtEQERFRNGtvb0d6enowv+gPk7dh6LlUmpyczOSNiIiIZHGtqVhcsEBEREQURZi8EREREUURJm9EREREUYTJGxEREVEUiaoFC2azGW1tbaioqBjyMWw2G0pLSwEAqamp0Ov1wzoeERERUThFfPJWWloKm82G3NxcVFZWwmQyDflYNTU1KC8vR3V1NQwGAwDA6XSitLSUCRwRERFFBUGSJEnpIAYqOzsbOTk5qKysHPRzrVYr8vLy0NLSAr1eH7y/sLAQFosFDodj0Mdsb2+HTqeDy+ViqRAiIiIaloHmFRE/8iaXwsJCFBcX90rcACA/Pz84CkdEREQU6UZE8maxWGCz2VBWVnbFY8XFxQpERERERDQ0I2K1aWVlJQwGwxWjbkRERETRZkSMvFmt1uClUbPZDADQ6/Vobm5GWVnZgJO67u5udHd3B79vb2+XPVYiIopdfr8fXq8Xfr9f6VBIZqIoQqPRXHNrKzmMiOTNZrPBaDTCbDZjzZo1ve7Pzs5GQ0PDgBK48vJyPPXUUyGMlIiIYpHL5UJ7ezsuXrzIxC2GaTQaJCUlYcyYMVCpVCHrZ0SsNhUEAQaDAbW1tVcsTigpKYHdbkd1dfU1j9PXyFt6ejpXmxIRUZ8kScLp06fhcDiQmJiI0aNHIz4+HqIohmWEhsJDkiT4fD6cP38eLpcLcXFxSE9PH3QCx9WmfehrVWl2djZKSkrgdDqvOfoWFxeHuLi4EEVH0UCSJPh9bvh93fD73JB8Hvj93sB9fk+v7yW/B35f4Cb5PfD7PZee4/38a78Hft9l7S89J3AcDwRRDZU6ASpNIlSa+MC/6gSoNQmX3d/X1wkQVXH85UCkMIfDAYfDgQkTJiAlJUXpcCjERo8eDZ1OhyNHjuDcuXMYP358SPoZMclbf+VAeu6vr68fVgFgigyS5IfP2wWfpxN+bxd83s5+vu8K/Ou9dL8ncH+vNpf+9V/W1uftAqQoueQhiMFErie56530xUOlToRaOwpxo8YjfvQExCdNRMLoCVDHJSkdPVHUkyQJTqcTSUlJTNxGkISEBCQnJ6OjowPjxo0LyR/RIyJ5G0gdN5vNFoZISA5+vxdd50+h03UEF13HcNF1BBfbj6DTdQydHcch+b1hi0VUaSGIGogqDURRA0F12deiBqJKC1GlDnx96XtBpf78a1EDUaWGKGoDz710rMDXakh+H3yei/B5O+H1dMLv6YTXezGQbHo64fNeDCSil9r4PJ3w+y5d2pf88HkuwOe5MOifS6UdhYTREwMJ3eiJiE+6/OsJiEscA0EYEYvViYbM6/Wiu7sbY8eOVToUCrOkpCQ4nU54PB5otVrZjz8ikjej0XjN5CwnJydM0dBASH4fOs+fRKfrKC66juKi6wg62wNfDzRBE9XxgVEmdfyl0ad4iMHv4wP/qhMutQu06fWcy54bbNPzvSoOgqiOyMuSkt8XTOSC/3ouwhv8/uJl93fC625H1/nT6Dp/Cl3nT8LT5YLPfQHn7Ydw3n6ozz4EUY34UeMRn3Qpobs0ahdM8EZPgErNKQY0svl8PgCAWj0iftXSZXrmuoVqccqI+B9VVFSEwsLCPh/rSeq4y0L4SX4fus6fCoycuY7iYvvRwGha+1F0tl89QRNVcUhInoJEXToSk9ORoJt66esp0MTrIarjIzKxCgdBVEGtHQ21dvSQnu/1XET3+dPo7DgZTOi6Lvu6+8JZSH4vOjuOo7PjeL/H0SakXpbYTUCibjp04+ZjVGomRHFEfPQQAcCI/SwayUJ9zmPqE9TpdPY5d62goAB6vR41NTUoKCjo9Vh1dXWf22bR8Ph9bni6XPB0t1+6udB94Uxg5Mx1NHCZ85oJmhYJyelI1E1BYvLUSwnaFCTqpiJu1DhetgsRtSYR6pQMjErJ6PNxv98L94Wz6Awmdpf+PX8KXR0n0Xn+JPzeLrg77XB32tF+dk+v54vqOCSNmQPd2AVIHjcfyePmIyFpMn/BERENUFQlb06nE3a7vd/HezaZr6ysvGLbq+rqapSUlMBkMgUTtaqqKthstgGVCRmp/D4PPN2BJMzb5YK72wVvVyAZ+zw5u/xrJ7xd7fB5Owd0/ECC1jOCNhUJuvTgaFrc6PFM0CKQKKoDl0iTJgLIuuJxSZLg6Xb1Gq3r6jiF8/aDcJ3dA5/7AlyndsJ1amfwOZp4HZIvJXO6cfORPHY+tAmc4E1E1JeIT97MZjNqa2ths9mCt+zsbBgMBhQVFfUaScvPz0d9fX2f89dMJhMqKyuxatUqpKamwm63w2AwoLm5OZw/TsTpOn8aJ/a/iu6LZ+HpcsH7hWTM57k49IMLIjRxSdDE6aGJS4Y2MfXSSNpUJCYHkjQmaLFHEARo4/XQxuuRPHZur8ckyY+LzsNwnd2D9jOBW0fbfni6XGg7+gHajn4QbJuQNDk4MqcbOx9JY+ZApUkI949DRBRxoqpIb6QZaDG9SOTucqK18Tkc27MJfp/7Gq0FaOKSoYnXQR2XDE2cDpp4XeC+y7+O10Ed1/O1HmrtKCZmdE1+nxsdbQfQfmYPXGf2oP3sHlx0tl7RThBUGJWaCd3Y+ZeSugUYlZLB+XMUsbq6utDS0oKMjAzEx8crHQ6F0VDPPYv0Up+8nos4susFHN75B/jcgRIS+glZSJmc20dCFvhXrR3NJIxCRlRpoRu3ALpxC5B+6T5Pdwc6zu6F6+zuS0ndbrgvnsP5tgM433YAx/e9HHiuOh7JY+Z+frl13ALEj57I+XNEBABXbIsZK5i8jRB+nwfH925Bi3UD3J2BeYOj02ZjxpLvIy39Rv6yo4iiiUtC6pQlSJ2yJHhf14UzaD+z+7IRus/g81yA81QjnKcag+0SktMxZtqtGDv1VugnZkFUaZT4EYgoAsTq1CgmbzFO8vtw6tBf0Fz/LLo6TgAI/HLLzF2N8Zn5HFGjqBE/ahziM5ZiXMZSAJfNnzuzG+1nPwvOn+tsP4qju17A0V0vQKUZhbQpN2DMtFswZuot0CakKvxTEFG42Gw21NfXIzMzM1iFwmazoba2VuHIho/JW4ySJAnnDr+LQ3W/wgV74C8PbeIYGLKLMWn2AxyNoKgnCCJGXSppMmn2/QAAr/sC7Mc/xrnD7+Pckffh7mzDmZbtONOyHYCA5HHzg6Nyo9NmccSZKEaVlpbCbDbDZDLBYDAEq0zESk1XJm8xyHHCikOf/AKu058CANTaJEzP+jbS56/kaj2KaWrtKIy7NDonSX60n92Lc0fex7nD76Hj3N5Ll113w1b3DOJGjcOYqbdgzNRbkTo5l+8NohhRWFiImpqaPsuGxQombzGk49x+HPrkV8FyC6I6DlMXPIxpi78JTVx0rYYlGi5BEKG7tJAhM6cE3RfOBhK5I++h7djH6L5wBsf3bsHxvVsgquKQMjkHY6feijFTb7lUw46Ioo3ZbEZNTQ2Ki4tjNnEDWCpkWCKlVMhF11E01z2D081bAQS2R5o850FkGB9F3ChuiEz0RT5vNxwnGi6Nyr2LrvMnez0+OnUGxky9FWOm3QrduAUQRJVCkVI0Y6mQ8OuZCuFwOBTdOYmlQqhf3RfOwtawHif2/xmSP7AB8oQZX4Ih5zEk6tKv8WyikUuljsOYqTdhzNSbIN38BC44bDh35D2cO/wenKc/xXn7IZy3H0Jr03PQxOuQln4Lxk67BalTboQmLknp8ImoD5fvVR7rW14yeYtCnu52tDb9Dkd3vwS/txsAMGbqLchc8j0kpc1SODqi6CIIAkanZmJ0aiamL/4W3F1O2I/+DWePvIe2Ix/C0+XCqYNv4NTBNyAIKugnLsbYaXdg/IxliEtMUzp8igGSJAFuj9JhhIdWE7KFQj2LEXqSuFjG5C2K+DydOLL7RRxu+j287vMAAN2ERZix5AdImXjlHpNENHjaeD0mzLwbE2beDb/fC9epT4OjchecLXCcaIDjRAMOfvRTpKXfhImz78fYabdCVGmVDp2ilduD7rKfKh1FWMSV/wMQF7r3SmVlJUpKSlBSUoLs7Oxgnbfc3Nxe22lGOyZvUcDv8+DEvj/DZl0P98U2AIE5OZlLvocxU29luQOiEBFFNVImGZEyyYiZN/w9LrYfw7nD7+HUob+g/czuQFJ35D1o4nQYP2MZJs66D8lj5/E9SaSQ4uJi1NbWoqqqCkajEdu3b4fdbkdhYSFMJlPMXE7lgoVhCPWCBUny4/ShrWiufxad7ccABDbrNuQ+hgmZyziJmkhBFxwtOHngdZw8+Ca6L5wJ3j8qxYCJs+7DxJn3cMHQCDfQSeu8bCqfnhIhJSUlsNvtaG5uRlpaGoxGY7BQbziEesECk7dhCGXydrH9GD7d9gTOtx0AAGgT0pBhfBST5z7IArtEEUTy+2A//glOHngdZ1reht8XmIcKQUTalBsxcdZ9GDv9dqjUccoGSmHH1abhZTabUVdXh+rqaqVD4WrTkSoucSw83S6otKMwfdG3MHXhV1lElCgCCaIKaek3Ii39Rni7O3DaZsGJA6/BdWon2o5+gLajH0CtTcL4zLswcdZ90I1fyMuqRDKzWq2orKwc9l6mJSUlqKyslCmq0GHyFqFU6jhcl29GQvIUaOP1SodDRAOgjkvC5LkPYvLcB3HRdSRwWfXAG+g6fwrH927G8b2bkaibFrisOusexI+eoHTIRDFh1apVqKioGPZx7Ha7DNGEHpO3CKYbt0DpEIhoiBJ1U5GZ+10Ych6D40Q9Th54Hadt23HRdRjNdb9Cc92vkTp5CSbOvg/jpt/JkXWiIbLZbLBarTG1mvRamLwREYWQIIhInbwEqZOXYPbNpTjTsh0n9r8O58kG2I9/DPvxj7FPMwrjM02YNOt+6CYs5mVVokGwWq0AAKfTGTOrSa+FyRsRUZiotaMwafYDmDT7AXS2H8fJA2/g5IHX0dlxHCf2vYIT+15BQvKUS5dV70MC91gluqae4ryrVq2KiMUK4SAqHQAR0UiUkDwZhpxi3PTVPyP7/vWYNPvLUGkS0dl+DLb6Z/HBC/fB+sb3cPbwu8Ht74joSj1lQGpqapCSkgKz2Qyn06l0WCHFUiHDECkb0xNRbPB5OnGm5W2cPPAa7MfrAAQ+nhOSJ2PKvEJMmv0ANPE6ZYOkAWOpkPAqLS2F2WwOfl9QUICSkpI+67uVlJT0uY1WfX09cnJy+mw/mDl1rPMWwZi8EVGodLYfx7HPanB835/h7W4HAIjqOEyYcTfSFzyEpLSZCkdI18LkLfycTifKy8tRVVUVHH0zGAyorq6G0Wi85vMLCwtlufQa6uSNl02JiCJQQvJkzLzh73Hr197E3Nv/BaPTZsHv7caJfX/GxzUPof6VR3G6uRZ+3wipzE80AHq9HhUVFXA4HKiurobJZILNZkN2drbSockq7MlbUVFRuLskIopaKk0CJs/5Cq5f8QJyHtiA8Zl3QRBVcJ5qxC7Lk/jghftha1iP7kv7HhNRQEFBAWpra4NFd2NpHtygV5s2NTUNuTObzQaLxTLk5xMRjVSCIEA/MQv6iVnounAGxz/bguN7t6D74lnY6p9Fi3UDxhvykb6gCMnjFrDcCI1YVqsVer0+uArV6XTG1Kb0wBCSt6VLl8LlcqGvqXI9Hxb9PSZJEj9QiIiGKX7UOGTmPoYM49/hjM2Co7s3wnVmF04degunDr2F5LHzMGX+SozPvIt7qtKIYzQaUVpaGqz7ZrPZYq6EyKAXLMyYMQPV1dUwGAzQ6T5f9eRyuVBaWorCwsI+V2rU1dXBYrGgrKys1/OiGRcsEFGkaD/7GY7u3oTTzVvh97kBAJp4PSbPeRBT5q1APGvGhR0XLEQfq9U6oIUN1xJxq02ffPJJrF279or7N2zYgJUrV161M5fLherqajz66KOD6TJiMXkjokjj7nTgxL4/4+hn1eg+fzpwpyBi7PQ7kD5/JVIm5fAKSJgweRu5Qp28DfqyaV+JGxC4VHqtBEan0/V5SZWIiOShTUjB9KxvY+qib+Dc4XdxdPcmOE7U4WzLDpxt2YFRKZlIX7ASE2beA7UmUelwiWgIZNsea6B/yfEvPiKi0BNFNcZlLMW4jKU4b2/GsT2bcPLAG7jgaMa+98px6ONfYOLsB5A+vxCJuqlKh0tEgyBbqZBDhw4NqF1zc7NcXRIR0QCMTs3EnFvLcOvX38Ksm36ERN1UeN3ncXTXC/jwpeVoeusf0HbsY14ZIYoSsiVv+fn5WL169VXbrF69Grm5uXJ1SUREg6COS8LUhQ/jxqLNWHz3L5A29WYAEs4deQ+Nb3wXH1UX4fjeLfB5u5QOlYiuQrbLpnl5edi2bRvS0tJgMpmQm5sLvV4Pp9OJ5uZmbNq0CStXrsTy5cvl6pKIiIZAEESMmXoTxky9CRddR3B090s4se9VXHA0Y++7/4VDn/wSk+csx5QFKxE/apzS4RLRF8i+t6nFYsGTTz4Jq9UavM9gMKCiogIrVqyQsyvFcbUpEcUKT3cHTux/BUd3b0RXxwkAgCCqMM5gwtQFX4Vu/EKFI4w+XG06ckVcqZDB6Ak8VkV78ib5JaDjPKT2CxDGp0HQapQOiYgUJvl9OHv4HRzZ9RKcJxuC9+vGLUT6wocxLuNOiCp+VgwEk7eRK+JKhVxLa2srLBYLbDYb/vu//xtAoL5bQ0MDli5dKnd3dA1SZxekNhekNickuytwu+xreH2BhvFaqBbPhWrJAgjTJnFVMNEIJYiq4CrV9nP7cHTXizh1aCtcZ3bBtb0McaPGIX3+Skya+yC08XqlwyUakWQdeXvyySdhNpuh1+shCALa2j7fKLmxsRHbt2/H448/Lld3iouEkTfJ44XkcAUSNPuVSRo6u69+AFEA4rS92gnjUqHKXQBV9nwI+qTQ/gBEFPG6L7bh+Gebceyzarg77QAAUR2HiTPvRfrCr2J0ikHhCCMTR95GrqgZeVu/fj1sNhuam5uRkZGBzZs393o8KysLBoMBGzZsiJkdFsJB8ktA+/lgUubvSc7aXJDsTsB1/toHGZ0IIVUHIU0PIU33+depOgj6ZEAQ4G8+Al/dbvg/PQDpjB3eN96F9833IM6aDtWSBRAXzISgkX2gloiiQFxiGgw5xZie9S2cat6Go7teQMe5/Ti+dwuO792C1CnXY+rCh5GWfhMEQbYiBkTUD9l+G/esKO3R12U3nU6HlJQUubqMaVJnF9w//SMkezvg8129sVbzeTL2xSQtVQchTnvN/lQzp0E1cxqk5Sb4du6Hr243JNsx+Pe3wL+/BUiIgyprLlS5CyFMncDLqkQjkKjSYtKs+zBx5r1wnmzEkd0v4mzrX2E/9jHsxz5Gom4a0hc8hImz7+PuDUQhJFvylpmZ2ev7/q7GtrS0yNVlbIuPg+TsCCRuogghJflSYqaDkKrv9S9GJciWTAnxcVBffx3U118H/1kHfPW74avbDTg74PuwCb4PmyCMTwtcVs2ZDyF5tCz9ElH0EAQBKZOMSJlkRGf7cRzdsxHH9/0ZF12Hsf+DCjTX/QqT5nwF6QuKkJA0SelwiWJO2LfH4g4LAyMIArSrHwKSR0HQJUFQhf9ShDg2BeLdt0K97Bb4Dx2B75Ndgcuqp9vgff0deN94F+KcDKiWLIQ4PxOCmpdViUaahOTJmHXjP8GQXYKTB17H0d0v4aLrCI58+icc2fUCxk6/A1MXPgz9hMUcsSeSiWwZgcPhwJYtW4Lf9/UmXb16NbKzs4fch9lsRmlp6ZCeW1JSgpKSkmD9OafTCYvFgsLCwl416SKJOH0SxFSdIonb5QRRgGrWNGi/fh/invoe1IXLIEyfDEgS/Htt8Pz+FXT/5NfwbK6F/+gpbrFDNAKptaOQvqAosHvDl36K1MnXA5IfZ1t2oOHVR1H38iM40/I2JMmvdKg0gpjNZqVDCAlZV5vm5ORAEAQUFRWhubkZhYWFcDqdqKurQ1VVFUwmEzZu3DioY5aWlsJmsyE3NxeVlZUwmUyorKwcdGz5+fmwWCy97tPr9aiurobJZBr08YDIWG2qJP8Z++eXVS9bOCFMGAPVkkurVZNGKRghESnpvP0Qju56CScPvgm/L7CifVRKJqZnfQvjM++CKMb2aD1XmyqvpKRkSDnDcEVdkV6z2Ywnn3wycHBBgCRJ0Ov1qKiowKpVq4Z17OzsbOTk5AzpRJSWliI/Pz84ymYwGFBQUDCseEZ68tZD8vvhP3gYvk92w7/rwOe140QB4lwDVLkLIc7LhKBWKRsoESnC3WnHkV0v4uiejfC5LwAIXG6dtuhbmDT7Poiqay+qikZM3pRls9mCg0g9gzQ2mw21tbUh7ztqSoX0WLNmDdasWYOWlhbYbDYYDIaI2WXBZDINeZSN+ieIIlSzM6CanQGpswu+xn3wfbIL0pGT8O9phn9PMzAqASrjvEDZkcnjlQ6ZiMJIm5CKGUu+h2mLvolje6pxZNfz6Gw/jn3v/RdaGqowddE3MGXucqg0CUqHSjGitLQUZrMZJpMJBoMBer0eQGDgJhbIlry1trZi+vTpwe8zMjL6TNpWr16NZ555Rq5uKcIICfFQ37QY6psWw3+6Db663fDV7wbaL8D3XgN87zVAmDwOqiULoTLOgzCKH9ZEI4UmLgkZxu9g6sKv4vi+l3F45x/RfeEMDv7tf9Ha+BukL/gq0hcUQRM3cq9k0PAVFhaipqYGlZWVKC4uVjqckJBtJnx1dTV27Nhx1TYul6tXLTiKbeL4NGjuux1x/7IamkdXQFw0G1CpIB0/A+/L29H9b7+G+/evwLfXBsnPScxEI4VKk4CpCx/GzV99BXNv+2ckJE+Bp8sFW/2zeP/5+3Dw45+j+2LbtQ9E9AVmsxk1NTUoLi6O2cQNkPmyaUVFRb/7lzY1NWHp0qVwuVxydjkoNput16KF5uZmlJWVBYdTKTQElQjVvEyo5mVCutAJn/WzwGXV42fg37kf/p37Ad3oQO243AUQx6YqHTIRhYGo0mLy3Acxcfb9OGOzoKXxt7hgb8bhpt/j6K6XMGnOVzB90TcQnzRR6VApSvRUpKioqFA4ktCSNXmrra3Fli1bsHz58l73l5WVwWw2Iy8vD/X19XJ2OWA2mw1Wq7VXJm61WpGdnY2GhoYBJXDd3d3o7v58D9D29vZQhBrThFEJUN+aDfWt2fAfPw3fJ7vha9gDuM7DZ/kIPstHEAxTApdVF80e0O4QRBTdRFGNCTO+hPGZd+Hc4ffR0vgbtJ/ZjWN7NuL43hpMmHkvpi9+BKP005UONSQkSYLf26V0GGEhquNDVu/PZrMBQK85brFKttWm27dvR2pqKurr65Gbm4vFixejtbUVBQUFsNlsqK6uRl5eXnD1xVAMZ7VpfwoLCwEELvtey7/927/hqaeeuuL+kb7adLgkrxf+Pc3wfbwrsBVXz39JrQaqxXOgWrIAQsYUFvgkGiEkSYLjRB1arL+F40TdpXsFjDPkISPrO0gaM1vR+AZqoCsOfZ5OvP3bW8IYmXLu/M77IV2Y0vN7Qul6o1Gz2jQvLw9AYAP69evXY+PGjTCbzSguLu412hYpK0975ObmDrjwb1lZGf7pn/4p+H17ezvS09NDFdqIIajVUC2aDdWi2ZCcHfDV74Gvbheksw74PtkF3ye7IIxNgSp3YWBLLn2S0iETUQgJgoDUyUuQOnkJXKd3oaXxOZw7/A7O2Cw4Y7MgberNyMj6DvQTFisdKkWYysrKYFH+7Ozs4K5Oubm5wy4PFklkr/PW47HHHkN2dvYVtd2ampqwePHiIR0zFCNvNTU1KCwsRENDA4xG46CeyzpvoSNJEqSW44HkrWkf4PYEHhAEiLMzAiVHFszgllxEI0RH20G0Nj2H0821wKVdGvQTs5GR9W2kTrkhIkfmBzr6wsum8upZbWo0GrF9+3bY7XYUFhZi+/btYbucGjUjb1/07LPPoqysDB0dHUhK+nykpLS0FFu3bg1Vt30qKSkJFgr+op4TabfbwxoTXZ0gCBAMUyAapkD9YB58O/cHFjnYjsG/zwb/PhuQGH+pdtxCiFNYO44oliWlzcTCvP9GZs5jaG36PU4eeB3Okw1oPNmA5LHzMD3r2xg7/Q4IgrLbCQ6FIAiscSeTmpoaOJ1OVFdXw263o7y8HGlpaaioqIipeXCDTt6WLVs24LZtbW3B7BcI7CeqxIKFTZs29Vuct2eCY05OTjhDokEQ4rRQL1kI9ZKF8J+1B2rHXdqSy/e+Fb73rYHacbkLocpm7TiiWJaom4p5t/8LDNmrcHjnn3B83xa0n/0Mn257AqNSDDBkr8I4gykqkzgaHrPZjLq6urDsoKC0QSdvdXV1yMnJGfQlRkC55K24uLjfZcO1tbUjYmVKrBDHpkK85zaov3QL/Ptb4avbBf+uQ4Hacce3w/vaX6EyzoXqrpsgpumVDpeIQiR+9ATMvvlxZBj/Dkd2vYCjezbigsOGXZYyjE77HTJzH8OYqbdG5OVUkp/VakVlZWVwjlusG3TyZjAYsG3btiF32DPSFQo9yeEXR9lyc3NhtVqvSDidTidqamoGtNKUIosgilDNNUA113CpdtzewCKHY6cDI3MNn0F1w3VQm27kAgeiGKZNSMGMJd/D9EXfxOFdL+DIp8/jfNt+7PzLP0I3/jpk5q5G6uQlSodJIbZq1aqYr+12uUEvWBhOqY/hPj8zMxNGo7HfZCs/Px8Wi6XPLTF6Vp9cnsANdwEEFyxEHn/rCXi3vg///tbAHWoVVDcthjrvBghJoxSNjYhCz93pwOGdf8DRPRvh9wbqcqZMysWMJd+DbvzCsMbCjenDw2azITMzU/HyIJcL9YKFkK02vVxraysA9Nr7dKDMZjNqa2ths9mCo3ZGoxEGgwFFRUW9lv6azWaUl5dj+/btfV7WNZvNaGtrg9PphN1uv+L5g8XkLXL5m4/C89Z7kGzHAndoNVDdYoT6ziWcE0c0AnRfOIuWxt/i+N4tkPxeAMCYqbciM3d12OrEMXkLj56qEQ6HI2KmQEVN8vb000+jvr4eqampyM/Px/Lly9HY2AiTyYTU1FRkZWVBEARs3LhRju4iApO3yCZJEvwHDsP71nuQjpwM3Bmnher2HKhvz4WQEKdsgEQUcp0dJ9HSsB4nDrwWLDEy3pAPQ04JRqWEtu4ok7fw6NktqaCgIGKmQUVN8rZ9+3bYbLZedd1mzJgBo9EY3Ize5XJh/fr1ePzxx+XoUnFM3qKDJEnwf9YM71vvQzpxJnBnYjzUdy6B6hYjt+AiGgEuOA/DVl+J082XSlUJIibOvBeGnGIkJE0KSZ9M3sKnZ9qUXq9HWVkZiouLFR2Fi5rkbcOGDXj00UeD32/evBkrV66Ew+HoFcD69euvKNwbrZi8RRfJL8H/6X54//I+pDOX6vqNToQ67waobloMQcOCv0SxrqPtIJrrnsG5w+8AAARRjclzHkSG8e8QN2qsrH0xeQuv0tJSmM3m4PcFBQUoKSnps1SY1WodVC6yfv36QVXZiJrk7YtJ2WOPPYbt27fj4MGDV20XzZi8RSfJ74ffuhferR9AanMG7tSNhjr/RqiWXAdBrVI0PiIKPdeZ3Wiu+zXsxz4GAIiqOEyZX4jpi78FbUKKLH0weQs/p9OJ8vJyVFVVwel0AghUyaiurh5SibOhCnXyJlsVw7S0tF7fWyyWPrPd1NRUubokGhJBFKHKmQ/tk38HdeEyQJ8EuM7DW1ML99oN8H6yC5LPr3SYRBRCunELYLz318i+vwq6CYvg93XjyKd/wgcvPoDmumfg7e5QOkQagp7dlBwOB6qrq2EymWCz2ZCdna10aLKSLXm7vDBeY2MjbDYbSkpKerVpampiwUSKGIJKBfWNixD341VQP2gCkkZBsrvgfektuM2/gc/6GSR/5Cw9JyL5pUzKRs4Dv8Hiu3+OpDFz4PNcRIt1A95/8QG0Nj4Hn6dT6RBpiAoKClBbWxssB9YzEhcLZJvkU1BQgJUrVyItLQ0bN25EQUFBcAP6HTt2YNOmTaiursb27dvl6pJIFoJaDfWtRqiuXwjfB43w7vgY0lkHPH96HYLlI6i/dAvEhTP5hwdRjBIEAWOm3oy09JtwpmUHbPXP4oLDhkOf/BJHdr2I6VnfxuS5y6FSc4V6NLBardDr9TAYDAACSZvJZIqYMiJykLXOm8vlgsVigcFgQFZWFoBAUd6f/exnOHfuHKZPnw6j0Yjly5fL1aWiOOctNkld3fC91wDv23VAV6DIpzBlPNR33wpxTgaTOKIYJ/l9OHVoK2wNz6Kz/TgAIG70eBiMj2LirPshqjQDOg7nvCmntLQUTqcTer0eNpsN69evD2vyFjULFgaisbERDQ0NvValRjMmb7FNutgF7zt18L1bD3R7AADC9MlQ330LVDOnKRwdEYWa3+fBif2vocW6Ad0XTgMAEpLTMfP6H2KcYek1n8/kbeSKmgULA5GZmYna2tpwdkk0ZEJiPDR334q4/1cC1R25gFoNqfU4PM9shPuZl+DvKfxLRDFJVGkwZd5y3PTQy5h144+giU9BZ/tRfFr7BPa9Vw6/z610iDRCyZq87dixA7m5uZg5cybS0tJ63VQqFVJSUpCbmytnl0QhJ4xOhOaBOxH3/1ZBdYsRUInwHzwC90//CPcfX4W/p9wIEcUklToOU697GDc//CqmL/4WAODYZzWo+/N3gpdVicJJtsumjY2NyMvLQ3FxMTIzM9HQ0IDs7GykpqbCbrejoaEB+fn5WLFihRzdRQReNh2ZJLsLnr+8D3/DHkACoFJBdUsW1KYbuW8q0Qhw7siH2PP2P8PT5YJam4T5d/47xk6/7Yp2vGw6ckXNnLfVq1dj7dq10Ol0AALJXEpKSq/N6FtaWtDS0oKlS689VyAaMHkb2fzHTsP7+l/hP3A4cEdCHNSmGwNbbnG3BqKY1nX+FHbVPgnXmV0AgGmLHkHmku9CFD9/7/f8Ap8+fToSEviH3UjS2dmJ1tbWyJ/zZjQag4kbECiUZ7FYerXJyMiAzWaTq0siRYlTxkNTshKa4kIIE8cCnd3wvvZXdK/dAF/DHtaII4ph8aMnIPuB9Uhf8FUAwOGdv4f1tcfQfeFssI0oBn7F+v0s+j3S9Jzznv8DcpPtqF8sn5CRkYGGhga5Dk8UkQRBgGpOBrQ/egTqh+4GdKMBRzs8z78B90//AN/Bw0qHSEQhIqo0mH3z41iYXwGVZhScpxrx8eaHYT/2CQBAo9FApVLhwoULCkdK4dbV1QVRFKFWh+YqjGzJW8/V19bWVuzYsQMAoNPp8Jvf/KZXO642pVgkiCLUSxYirmwV1PfcBsRpIR07HViZWlUD/8mz1z4IEUWl8QYTrl/xJ4xOnQl3px3WN78Hm3UDAAlJSUlob29HGKtyUQQ4f/48EhMTQzbyJtucN5fLhfLyctTU1MDhcKCtrQ1OpxMGgwGZmZkwmUywWCzIycnBM888I0eXiuOcN+qPdP4ivNs+hO/DJsDvBwQBqiULoF52CwR9ktLhEVEI+Lxd2P++GSf2vwIASEu/CYYb/x9OnHIgOTkZkyZNYpHvEcDhcODUqVOYNGlSr+lkA6FYkd7Gxkbo9XpkZGQAQHCP0+3btyM/Px9bt26VsztFMXmja/GftcP7xrvwf3ogcIdGDdUduVDfuQRCPLfaIYpFJ/a/in3vr4Xf2424UeMx49b/hvNiHDQaDZKTk5GYmAiVSsVELoZIkgSv1wuXy4WOjg6kpKRgwoQJgz5ORO6wEGuYvNFA+VuPw/PqXyG1XqoJNToR6mU3Q3XDdRBUKmWDIyLZnW87iE9rS3HRdRiCqELGklLEj70R58+fh8/nUzo8CpG4uDjo9XqkpKQMKTmP2ORtx44dLBVCI5IkSfDvOgjvG+9AOusAAAhjU6C+7w6IC2bwr3CiGON1n8fed/4Tp22Bud7jMvIw97Z/hiTGcwVqDFKpVFCr1cP6LI/Y5G3ZsmUxc+mUyRsNheTzwffRp/Bu/QA4fxEAIGRMgeb+OyBOn6RwdEQkJ0mScHTPRhz82/9B8nuRkJyO6+4yIyltltKhUQRSJHnbsGEDqqurYbfb+21jtVpjZsiYyRsNh9TVDe+OT+B7pw7weAEA4qLZUN9zG8SxKQpHR0Rycp3ehV2WJ9F1/hREVRxm37IGk2Z/mSPu1EvYk7enn34alZWVMJlM0Ov1fbaRJAkbNmxAW1ubHF0qjskbyUFydsD7l/fhq9sV2G5LFKG6aTHUd90EYXSi0uERkUzcXU7seftf0XbkAwDAxFn3Yc4tT0Kl4e4LFDDQvEK26nHNzc04dOjQNds1NjbK1SVRTBD0SdA8dDdUt+XA+/o78O+zwfe+Fb763YHttm7LgaDmogaiaKeN12Pxl36K1qbfobnuGZw88Draz+3FdflmjNJPVzo8iiKyVY/Lzs4eULvKykq5uiSKKeKksdAWF0DzWBGEyeOALje8r78D97rnuFMDUYwQBBEZWd+B8d5fQ5uQhgv2Znyy5Rs4dWib0qFRFAlN6d+r6Kn/RkR9U82aBu0/PgLNV+8BRidCOmMP7NTwx1chOTuUDo+IZJA6ORfXr3ge+onZ8HkuYvf2Mux73wy/z610aBQFZEvecnJygttiXU1RUZFcXRLFLEEUoMpdgLiyR6G6xQgIAvyN+9BdsQHev34CKUYW/RCNZHGjxsJ4368xffG3AQDH9mxE/SuPorPjpMKRUaSTdbVpU1MTKisrMWPGDGRlZV3xuNPpRGlpKQ4ePChXl4riggUKF/+x0/BsqYXUegIAIEwYA81yE8QZUxWOjIjkcPbwu9jz9k/g7W6HOi4ZC+78d4yZdqvSYVGYhX21aWNjI/Ly8uB0Oq/aThAElgohGgLJL8FXtwve198BLnQCAETjPGgeuANC8miFoyOi4ersOIFdtU+i/eweAMCsm36EqQsfVjgqCqeB5hWyXTYtLS3F+vXr4XA44Pf7+731NSJHRNcmiALU11+HuCcfheqmxYAA+K2foXvtBnjfrYfkY8V2omiWkDQJOV/egCnzCgEABz78HxzdvVHhqCgSyZa8GY1GrFixAjqd7qrtOOeNaHiEUQnQFNwF7T98A0L6hMCq1D/vgPt/fw+/7ZjS4RHRMIgqLWbfUhqcB7f/AzOOfVajcFQUaWRL3mbMmDGgdk888YRcXRKNaGL6RGj//htQFy4DEuMhnTwL9y9fgPvFNyF1XFA6PCIaIkEQkLnke5i26JsAgH3vleP43pcVjooiiWzJmyRJaG9vv2a7LVu2yNUl0YgniALUNy4KXEq94brApdS63egu3wDve1ZeSiWKUoIgYMb1P8TUhV8DAOx9979wYt+rCkdFkUK25G3VqlXYtGkTmpqartqORXqJ5CeMToRm5Zeg/eHXIUwZD3R1w/uyBe6f/gH+1uNKh0dEQyAIAmbe+I9IX1AEQMJn7/w7Th54Q+mwKALIttp02bJlAID6+no4nU4YDIYr9jh1Op2w2WxcbUoUQpLfD9/fdsL75rtAZzcAQLVkIdT33c69UomikCRJ2P/+2sDcN0HEgjv/HRNm3q10WBQCYS8VkpqaCpPJBIPBgLS0tD7bnDt3jhvTE4WJdP4ivK+/A98nuwJ3JMRDfe+tUN2wCIIY9s1ViGgYJMl/ae7blkACt/S/MGHGXUqHRTIL+8b0BoMBmzZtumY7bkxPFB7C6MTAhvfXXwfP5lpIJ87AW1ML30efQrPiLojTJiodIhENkCCImHNrGSS/Dyf2v4I9O/4ZgqjCeEOe0qGRAmQbeWtpaRnQvqUul+ua5USiBUfeKFpIPj98HzbC+9Z7QJcbEADV9ddBfe/tEEYlKB0eEQ2QJPnx2V+fwskDr0MQVViYb8a46XcoHRbJJOyXTUciJm8UbaSOC/C89lf46wMV3JEYD/W9t0N1/XUQREHR2IhoYCS/D3ve/glOHXoLgqjGdXc9jbHTblM6LJJB2HdYGCgW6SVSjpA0CtqH74X2e1+FMGEMcLEL3uqtcP/qRfjP2JUOj4gGQBBVmHfnv2F85l2Q/F58um0Nzh35QOmwKIxkH3lramqC3d73LwFuTE8UOSSfD773rfC+9T7g9gBqFdTLboHqjlwIKi5oIIp0fr8Xu7f/GGds2yGqtFi07H+Rln6j0mHRMIT9smlLSwuys7O5MT1RlPHbXfBu2gr/gVYAgDBlPDRFd0OcPE7ZwIjomvw+D3ZZynC29W2Iqjgs/tJPkTplidJh0RDF5Mb0ZrMZpaWlcoUMs9kMi8Ui2/GIopGYqoOmpBDqh+4GEuIgHTsN9//9AZ633oPk9SodHhFdhajSYKGpHGOm3Qa/rxtNW/8B9hP1SodFISZb8pabmxuSjelLS0tRWFgIs9mMysrKa47sDVTPJVy5jkcUzQRBgHrJQsSV/h3EhbMAvx++2r/B/T+/h7/1hNLhEdFViCoNrsuvQNrUm+H3dqPprb+H4yTLcsUy2ZK3lJSUAbUb7Mb0FRUVqK6uxpo1a67YsWE4qqqqZDsWUawQkkdD++2vQPPIl4GkUZBOt8H9iz/B8+ftkLrdSodHRP0QVVpcl/800qbcCL+3C01v/gDOU01Kh0UhMiI3prdYLDCZTEqHQRSxVItmI27NdyDmzAckwPduA9xPPwffgcNKh0ZE/VCp43DdsnVInXw9fN5ONL75Q7hO71I6LAqBEbkxvdVqhdFoVDoMoogmjEqA9uF7oVlVAKQkQ7K74Hl2Izwb/wKps0vp8IioDyp1PBYt+x+kTMqGz3MB1je/B9eZPUqHRTKTbXusno3pe+aRXW1jeiVVVVVhzZo1isZAFE1Ucw0Qn/g2vG+8C98HjfB9/Cl8e23QFORDtWCm0uER0ReoNAlY/KWfofHNH8B5qhGNb3wPxvueQfLYuUqHRjKRLXmrq6uDyWTCqlWrrrkxvVJsNhtSU1OH/Pzu7m50d3cHvx/IZWKiWCDEx0GzIh+qrDmBkbezDnh++zJ8i+dAs9wEYXSi0iES0WVUmgQsvvtnaHzrB3Cd2gnrG99F9n3PImnMbKVDIxmMqI3pa2pqhjXqVl5ejqeeekrGiIiii2hIh/ZH34J324fw/fUT+Jv2ofvgYWi+kgfROBeCwC22iCKFWjsKWXf/HI1vfB+uM7tgfWM1su+rxOg0jphHO9nmvFVXV8vaTm41NTUoKCgY1jHKysrgcrmCt6NHj8oUHVH0ELQaaO67Hdq//waESeOAC53wPP86PL/ZDMnZoXR4RHQZtXY0su75BZLHzoeny4WG11fjvL1Z6bBomGRL3jIyMgbU7lp14ELB6XTCbrfDYDAM6zhxcXFITk7udSMaqcT0CdD+4zegvvsWQKWC/zMbus2/gfdvTZD8su66R0TDoI5LQta9v0LSmLnwdDlgff0xXHC0KB0WDUPYNzDsWdgQTlVVVSguLg57v0SxTlCpoM6/CdofPQJh2iSgyw1v9TZ4nnkJ/rMOpcMjoks0cUkw3vsrjE6bDXenHQ2vl+CCs1XpsGiIZJvztmPHjmu2sdlsqK8P77YdLAtCFHrihDHQ/uDhwEb3b74Hf/NRuNc9B/Xdt0B1Ww4EkRvdEylNE6+D8b5fw/paCc7bD8H62mPIfmA9EnXpSodGgyTbxvSpqalwuVzo73CCIECSpGFtTJ+dnY2cnJxB1YqrqanBxo0br7jf6XTCYrHAaDTCYDAgNTV10DXouDE90ZX8bc7ARvcHAwV9hakToSn6EsSJYxWOjIgAwN3pQMNrJbjgaEbc6PG4fvmfoE0YeiUGks9A8wrZkrcZM2agurq6z43nXS5XcAP4FStWDLmPoSRv/XE6nUhJSUF1dfWQFzIweSPqmyRJ8H28C95X3wa6ugGVCHX+TVDl3QBBxVE4IqV1X2xDw6urcNF1GCmTcmG891cQRJXSYY14A80rZPsULSgo6DNxAwKLFFasWAGTyRTS7bF6RtOISFmCIEB9w3WIK/0OxAUzAJ8f3r+8D/evXoC/zal0eEQjXlxiGq5btg4qdQIcJ+rQXPeM0iHRIMiWvK1du/aabXQ6Hdra2obcR8+q0f4UFhYiPz9/QJvO9xznascjouERdEnQfPtBaL52HxAfB6n1BNzrfgdfPbfrIVLa6BQD5t7+rwCA1qbncLb1HYUjooEK+/WLwRbxNJvNyM/PR2ZmJmw2G2pqapCdnY3CwkLU1NT0apufnw+9Xo+cnJx+j2e1WpGfn4/8/HwAge28BprwEdHgCYIAVfY8xD3+LQgZU4BuNzwvvAH3n16D1Nl97QMQUchMmHEX0hd8FQCw5+1/xUUX65dGA9nmvA1Ee3s7SktL8cwzsTE8yzlvRIMj+fzwbf8I3m0fAH4JSEmG9uv3QcyYonRoRCOW3+dBw2slcJ3eidGpM5H7leeg0iQoHdaIFPYFC7m5uVd9vGdT+traWixdulSOLhXH5I1oaPytJ+B5/nVIbU5AEKDKvxHq/Ju4mIFIIV0XzuCTzV+Du9OOibPuw7w7/o3b3SlAkdWmRqOx3yROr9dj5cqViuywECpM3oiGTurqhmeLBf5L89+EaZOg+fp9ENP0ygZGNELZj9fB+sZ3AcmPObf+P0yZt1zpkEacsCdvOTk5YS/AqzQmb0TD52vcC0/1tkBJkTgtNCvyIWbP41/9RApobfo9Dn38cwiiBjlf/g104+YrHdKIEvZSIdu3b5frUEQ0gqiy5l6xmMHzp9chdXYpHRrRiDNt0TcxdvodkPwe7KpdA3eXU+mQqA+yJW+xdDmUiMJLSNVB+72HApvciwL8jXvRve538NuOKR0a0YgiCALm3/FvSEhOR9f5U9iz/Z8h+Ye2KxKFDmcHE1FEEMTALgzaH3wNQpoecLTD/asX4XnrPUg+v9LhEY0Y6rgkXHfX0xDVcWg79jfYrBuUDom+gMkbEUUUcdokaH/0CMTcBYAkwVf7N7h/+QL85xxKh0Y0YiSlzcTcW/8fAKClYT3OHflA4YjockzeiCjiCPFx0H71Hmi+cX9gZ4bDJ+D+n9/BV7cbYSxNSTSiTZx1L6bMKwAgYfeOf0ZnxwmlQ6JLmLwRUcQKLmYwTAG6PfC8+CY8f3yNixmIwmTWTT9C8rj58Ha349Nta+DzcleUSMDkjYgimpCqg/a7D0F9962BxQxN+y4tZuA2PkShJqq0uM5UAU28Dh3n9uLAB08rHRKByRsRRYHAYoYbv7CY4aVLixm4Eo4olOKTJmLB0v8CIOD4vpdxYt+rSoc04jF5I6Ko0edihl9wMQNRqKWl3whD7mMAgH3vr0X7uX0KRzSyyZa8lZWVyXUoIqJ+XbGY4chJLmYgCoOMrO9gzNRb4Pd1Y9e2NfB0tysd0oglW/JWVVWFnTt3ynU4IqKrUmXNRdwT3+ZiBqIwEQQR85f+B+KTJqGz4zj27PhXSBJrMCpBtuTN4XBgzZo1KCsrQ1NTk1yHJSLql5CSHFjMcM/nixnc//cH+E+dUzo0opikiUvGdflmiCotzh15D62Nzykd0ogkW/JWUVGBrVu3ory8HG1tbXj66aexYQOrMhNRaAmiCLUpsJgBKcmQzjnh/tkf4fv0gNKhEcWk5LFzMfuWJwEAzXXPoO3YRwpHNPIIUggnibhcLmzatAkulwsmkwmLFy8OVVeKaG9vh06ng8vlQnJystLhEI140vmL8Pz+FfibA2VEVPk3Qr3sFgiioHBkRLHns3f+HSf2vQJNvB7Xr3ge8aMnKB1S1BtoXhHS1aY6nQ6rVq3C448/jvr6euTm5nI0johCRhidCM1jRVDdlg0A8NX+DZ7fbOY8OKIQmH1zKZLGzIGny4lPa0vh97mVDmnECHmpkC1btiA3NxfFxcVwOBxITU0NdZdENIIJKhGar+RB8/C9gFoN/14b3D/9I+fBEclMpY7DdflmqOOS0X5mNw787f+UDmnEkC1527JlS/DrpqYmrF69GmlpaSgoKEB2djYaGhpw6NAhLF++XK4uiYj6pcqZD+0PHwb0SZDOOgLz4HYdVDosopiSkDwZC5b+BwDg2J5NOHnwTYUjGhlkm/M2c+ZMlJSUYOPGjbBarcjKykJJSQlWrVolx+EjEue8EUU+zoMjCr3mumfQYt0AUR2HJV/5PUanzVQ6pKg00LxCtuRNFEUIgoBVq1ahpKQEWVlZchw2ojF5I4oOks8H76t/he+9BgCAOM8Azdfug5AQr3BkRLFB8vvQ+NYPYT/2ERJ1U7HkwT9AHZekdFhRJ+zJ24wZM9DQ0ACdTifH4aICkzei6OKr3wPPpr8AXh+EsSnQfGc5xPFpSodFFBPcnQ58suXr6Dp/CmOn34nr7noagsAR7sEI+2rTgoKCYOK2Y8cOrFu3DkVFRSgrK8PLL78sVzdEREOmypkfqAfXMw/up5wHRyQXbUIKFuabIYganG19G4d3/lHpkGKWrHXeWltbUVxcDIvFAgDQ6/VwOp0AgOzsbNTU1GDatGlydac4jrwRRSep4wLcf3gVEufBEcnu2Gc12PdeOSCIMN73DFIn5SgdUtRQpM5bQUEBCgsL4XA44Pf7Ybfb4ff70dzcjMLCQhQUFKC9nRvZEpGyhKRR0D62EqpbL6sH99stkDq7FY6MKPpNnrsCE2fdC0h+7Lb8GN0XziodUsyRbeRt3bp1WLFiBTIyMvptY7PZsH79epSXl8vRpeI48kYU/Xx1u+Gp3hqYBzcuFZpvP8h5cETD5PN0ou7P38Z5+0HoJixC9n2VEFUapcOKeGEfeZMk6aqJGwAYDAYW6SWiiKLKXQDtDy7VgztjD8yD2815cETDodIk4Lq7noZKOwquUzvRXPdrpUOKKbIlb3q9fkDtuPKEiCKNmD4Rcf/4TQiGKUC3G57fvgzPX96H5A/Z1s9EMS9Rl475d/wbAODwzj/CeapJ0XhiiWzJ20CTsra2Nrm6JCKSjZA0CtrVRVDdYgQA+LZ9CM9zL3MeHNEwjMtYiomz7gcgYc/bP4HP06l0SDFBtuQtJSXlmpvOl5WVITMzU64uiYhkJahU0Cw3QfPVewC1Cv49h+D+2R/hP80/OomGavZNP0Lc6PHobD+Ggx//QulwYoKspUJWrlyJlpYWPPTQQ8EdFpxOJ2w2GyorK2E0GrFx40a5ulMcFywQxS7/kZNw/+7PgLMDiNNC87V7oVrALX+IhqLt2EdofON7AADjvc8gdcoShSOKTGHfYaFHVVUVnnzySTidTgiCgJ7DV1RU4IknnpCzK8UxeSOKbVLHBbh//wok2zEAgHrZzVDl38R6cERDsO+9chz7rAbxoyfghsKNUGtHKx1SxFEseevR0tICm80Gg8FwzVWo0YrJG1Hsk3w+eF95G773rQAAcf4MaL52L4T4OIUjI4ouXs9FfFzzEDrbj2PSnC9j3u3/qnRIEUfx5G0kYPJGNHJ4P9kFb822z+vBrSqAmKZXOiyiqOI42YiGV1cBkLD4Sz/FmGm3Kh1SRAlZ8rZ582Y4HI4r7s/JycHixYuD37tcLmzfvh0mkylmExsmb0QjS695cEmjoF1VAHHKeKXDIooqB/72vzjy6fPQJo7BjYWboInXKR1SxAhZkV6j0Yht27ahpKQEJSUlaGhoQEpKCgwGQ692Op0OWVlZ2LhxI8rKytDa2jroH4KIKJKIUyci7odfhzBxLNBxAe5fvQDf/lalwyKKKpm530WifjrcF89h/wdmpcOJSkO6bNrS0oLS0lJUVFQMeD7b008/jezsbCxdunTQQUYqjrwRjUxSZzc8z70M/6EjgChC89DdUOXMVzosoqjhOrMbdX/+NiD5sTDfjPGGPKVDiggh3R7rySefxKZNmwa1EOGJJ57Atm3buDE9EUU9ISEOmuICiFlzAb8fnhfegHfHx+AUYqKB0Y1bgOmLvwUA2Pfef8PdaVc2oCgz6ORt3bp1WLt27ZA6Kysri5lN6YloZBPUami+dh9Ud+QCALyvvwPvy9sh+f0KR0YUHQzZqzA6dSY8XU7sfa+cf/wMwqCTt7q6uiGX/tDpdLDZbEN6LgCYzWaUlpYO6blOpxNmszk4V6+kpASFhYWwWq1DjoeIRjZBFKB54E6ov3wnAMD3vhWeP7wKyeNVODKiyCeqtJh/51MQRBXOtuzAqUNvKR1S1FArHcC1lJaWwmazITc3F5WVlTCZTIM+htPpRHl5OcrKyqDX64P319TUIDs7G7W1tUM6LhERAKhvz4WQPBqeF96E/9MDcJ/fBO13lkNIjFc6NKKIljRmNjKyi2Grewb73zcjdVIu4kaNVTqsiDfokbfhjJwN5fkVFRWorq7GmjVreiVeg7Fp0yZUVVXBbu99Tb2goAB6vX7Io3lERD1UWXOhKSkE4uMg2Y7B/YvnITk4x5foWqYv/haSx86D192Bz975D14+HYBBJ2+SJA1r0YESJyU1NRVAYASOiChUVDOmQvv9hwHdaEin29D98z/Bf+Ks0mERRTRRVGPenU9BVGnRdvQDnNj3Z6VDiniDTt6KioqGvOhg3bp1KCoqGtJzh6OgoAAOhwNGo/GKx5xOJ3JycsIeExHFJnHS2EAtuPFpgOs83L98Hr6Dh5UOiyiijU4xIDP3uwACRXw7O04oHFFkG3Ty9sQTT6CyshI7d+4c1PMaGxtRXl6OkpKSwXYZMmZzoDggL5sSkZyElGRof/A1CIYpQJcbnqoa+Br3Kh0WUUSbuvBh6CYsgs9zEZ/99SlIEldu92dIdd6qqqpgNBrx8ssvD6j95s2bkZOTg/Xr10dMMVun04nKykpUV1dfsTtEf7q7u9He3t7rRkTUFyExHtqSlRCvmwX4fPD88TV436lTOiyiiCWIKsy/4ymI6ng4TtTj2J5qpUOKWENabVpQUIDy8nKsWLECOTk5KCoqQl5eHgwGA5KTk9He3g6bzQaLxYKNGzfCarVi7dq1WL58udzxD5rZbEZzczPsdjtqa2sHnLgBQHl5OZ566qkQRkdEsUTQqKH55gPw/nkHfO9b4X3lbUjODqjvvxOCKCgdHlHESdSlY+b1f4/9H1Tg4Mc/Q1r6jUjUTVU6rIgzpO2xelgsFpSUlKClpQWCcOUHkSRJMBgMqKysRF7e8Le+yM7ORk5ODiorK4d9LIvFgoqKCpSUlKCgoGBAz+nu7kZ3d3fw+/b2dqSnp3N7LCK6KkmS4Hv7E3hffwcAIGbNgear90BQR3y1JqKwkyQ/Gt/4HuzHP4Fu/CLkPLAegqhSOqywGOj2WMNK3nrU1NTAYrGgvr4eTqcTer0eOTk5yM/Px4oVK4Z7+CA5kzcgcOk0JSUFlZWVKC4uHvTzubcpEQ2Gr34PPC+9Bfj9EGdMhebbD0JIiFM6LKKI09VxEn+rLoLPcwEzrv97TF/8TaVDCouwJm/hInfyBgCFhYWoqamBw+EYdB05Jm9ENFi+/a3w/O5loNsDYeJYaFcVQNAnKR0WUcQ5vu8V7H3n3yGIGly/4nmMTs1UOqSQC+nG9LEkNzewL6HFYlE4EiIaCVSzp0P7vYeBpFGQTp4N1II7dU7psIgizqTZDyBt6s2Q/B7sefsn8Ps8SocUMUZE8paSkoLCwsI+H+sZbRvuzhFERAMlThkP7d9/HcK4VMDZAfcvnoffdkzpsIgiiiAImHfbv0Adl4yOc3vR2vSc0iFFjJhP3pxO51V3VmhubgaAQa06JSIaLjFVF6gFN30S0NkN97Mb4fv0gNJhEUWUuFFjMeeWQC3WFusGtJ/bp3BEkSGmkjen03nF5U+9Xo/i4mJUV/ddL8ZisUCv1w94xSkRkVyEUQnQPlYEcf4MwOuD5/d/hvc9q9JhEUWU8ZnLMC4jD5Lfhz1v/yv8PrfSISkuqpI3p9N5xebylyssLER+fj6qqqp63V9aWoqSkpIrRuCqqqpgtVqxffv2UIRLRHRNglYDzbe+AtWNiwAJ8L5sgef1d7g5N9ElgiBgzq1l0MSn4IK9Gbb6qms/KcZFfJEhs9mM2tpa2Gy24C07OxsGgwFFRUW9Rszy8/NRX19/xV6lPbXmerbB6kkCU1NTh7TKlIhIToJKhLrgLgj6JHjfeh++HR9Daj8PzcovQVCPjPpWRFejTUjB3Nt+jE+3PYHWnb/H2Om3Qzd+odJhKSaqSoVEGpYKISK5eT/ZBe+mvwB+CeIcAzTf+jIErUbpsIgiwu4d/4JTB99Eom4arl/xPFSaBKVDkhVLhRARRSH1koXQ/N0KQKOGf58Nng2bIXVzjg8RAMy++QnEJY7FRddhHKr7tdLhKGbAyRs3YiciCg/VXAO0JYVAnAb+Q0fgrqqG1Nl97ScSxThNXDLm3v4vAICju16E40SDwhEpY8DJW11dHYxGI5YtW4YtW7aEMiYiohFPNKRD+1gRkBAHqeU43M9uhHShU+mwiBQ3ZurNmDTnKwAkfPbXp+D1XFQ6pLAbcPKWl5eHQ4cOYe3atfjkk08wY8YMFBUVMZEjIgoRcdokaFc/BIxKgHT0FNy/fglSxwWlwyJS3Kwb/xHxoyeis+M4Dn70U6XDCbtBz3nLysrC2rVrcejQIRQXF2Pbtm2YOXMmVq9ejR07doQiRiKiEUucMh7a7301uJ2W+9cvQXJ1KB0WkaLU2tGYd8dPAADHP9uMtqMfKhxReA1rwUJeXh6effZZHDx4EAUFBXj22WeDiVxTU5NMIRIRjWzihDGBBE6fBOl0G9y/ehGSg3OQaWRLnZyL9AVFAIDP3vkPeLpHzh81sq02zcvLw6ZNm3Dw4EGYTCasWbMGM2fORFlZGVpbW+XqhohoRBLHpUL7va9CSNVBOudE9y9fgP+cQ+mwiBQ1Y8kPkKibiu4LZ3Dgw3VKhxM2ISkVsmLFCmzbtg319fUwGAwoLi7GzJkzsW7dOiZyRERDJKbpof3+wxDGpgCOdrh/+SL8p9uUDotIMSpNAubd8W+AIOLkgddxpuVtpUMKi5DWedPpdFi1alUwkdPpdCgoKEBubi7WrVvH0iNERIMk6JMCI3ATxgDt5+H+1YvwnzirdFhEitFPWIRpi74BANj77n+i+2Ls/0ETtiK9PYlcfX09Nm3aBEmSsHTpUixbtgwbNmxgIkdENEBC8mhov/sQhMnjgPMX4f71i/AfPaV0WESKycx5DKNTZ8LT5cTed/8z5vcGVnx7rJaWFlRWVqKxsRFbt25VMpRB4/ZYRKQk6WJXoIDvkZNAvBbaVYUQMyYrHRaRIs63HcTHW74Bye/B3Nv/BZPnfEXpkAZtoHmF4slbNGPyRkRKk7q64d6wGZLtGKDVQPPoCqhmTFU6LCJFtDb9AYc+/hlUmkRcX/AiEpOnKB3SoHBvUyKiEUCIj4O2uBDirGmA2wNPVQ18+1qUDotIEdOu+xr0E7Lg81zEZ2//BJLfp3RIIcHkjYgoyglaDTR/twLiPAPg9cLzmy3w7T6odFhEYSeIKsy/8ymoNIlwnmrC4U//qHRIIcHkjYgoBggaNTTfehDidbMAnw+e370CX9M+pcMiCruE5MmYfdMTAIDmumfQ0XZA4Yjkx+SNiChGCGoVNN94AKJxHuD3w/PH1+Cr36N0WERhN3H2/Rg7/XZIfi/27PgX+H1upUOSFZM3IqIYIqhEaB6+B6rrFwKSBM+Lb8D7tyalwyIKK0EQMPe2f4Y2IRXn7YfQXPeM0iHJiskbEVGMEUQR6sIvQXWLEZAAb/U2eN9tUDosorDSJqRi7m3/DAA4vPOPcJywKhyRfJi8ERHFIEEUoH4wD6o7lwAAvH/eDu/2jxWOiii8xk6/HZPmfBmAhD1v/yu87vNKhyQLJm9ERDFKEASo77sdqrtuAgB433gHnr+8H/PV54kuN+vGHyEhaTK6zp/E/g//R+lwZBH25K2oqCjcXRIRjViCIEDzpVugvvc2AIBv24fwvv4OEzgaMdTaUZh351MABJzc/yrOtP5V6ZCGTT3YJzQ1NQ25M5vNBovFMuTnExHR0KjzbgA0Gnj/vB2+tz8BPF6ov5IHQRSUDo0o5FImZmHaom/i8M7fY+87/wn9+OugTUhVOqwhG3TytnTpUrhcrj7/ahOEwIdAf49JkhRsQ0RE4aW+LRvQqOCt2Qbf+9ZAAld4FwSRM2go9mXmPoa2ox/ivP0gPnvnP7Fo2f9EbU4y6Hdsamoq6uvr4XA44Pf7gzeHw4FVq1Zh27ZtcDgcV9y2bt2KNWvWwG63h+LnICKiAVDfuBiah+4BBAG+jz+F54U3Ifn8SodFFHKiSov5S/8DgqjBucPv4MT+V5UOacgGPfJWUFCArKysK+6vrq6G2WzudyNVk8mE3NxcVFdX49FHHx18pEREJAtV7gJAo4bnT6/Db/0MHq8Xmq/fD0GtUjo0opBKSpuJzNzv4tDHP8OBD9chZVJ21G1eDwxh5G3t2rV93i9JUr+JWw+dTsdJskREEUC1eA403/oyoFLB/+kBeJ57GZLHq3RYRCEXC5vXyzbRYaDXjaP1+jIRUaxRLZgJzaPLAY0a/r02eDZshtQdW9sIEX3RlZvX/0npkAZNtuTt0KFDA2rX3NwsV5dERDRMqtkZ0BYXAnEa+A8ehruqGlJnt9JhEYVUQvJkzLrpcQA9m9cfVDiiwZEtecvPz8fq1auv2mb16tXIzc2Vq0siIpKBmJkO7WNFQEIcpJbjcD+7EdKFTqXDIgqpSbMfuLR5vQd7dvxzVG1eL1vylpeXh+TkZKSlpaGoqAjr1q3Dhg0bsG7dOqxevRppaWkAgOXLl8vVJRERyUScNgna7z4EjEqAdPQU3L9+CVLHBaXDIgqZaN68XpBkXkFgsVjw5JNPwmr9fANYg8GAiooKrFixQs6uFNfe3g6dTgeXy3XNxRpERNHAf+oc3M9sBDouQBiXCu1jRRD0SUqHRRQyZ1vfwc6t/wRAQPb9VUiZZFQsloHmFbInb5draWlBRkZGqA6vOCZvRBSL/GftgQTO2QEhTQ/N6iKIqTqlwyIKmc/++u84sf8VxCdNwg0FL0KtHa1IHAPNK2Qvq93a2ooNGzbgxz/+cTBxc7lc2LFjh9xdERFRCIhjUxH3/YchpOkhtTnh/uUL8J9hgXWKXbNuurR5fccJHPjwf5UO55pkTd6efPJJGAwGrFmzBpWVlcH7dTodUlJSsG7dOjm7IyKiEBFSddB+/6sQxqcBzg64f/Ui/CfPKh0WUUhcvnn9if2vRPzm9bIlb+vXr4fNZkNzczPsdjuqqqp6PZ6VlYVVq1Zhw4YNcnVJREQhJOiSoP3uQxAmjQM6LsD965fgP3ZK6bCIQqJn83oA2PvOf8LdGbmjzbIlb83Nzdi0aVPwUmlfxXh7RuCIiCg6CEmjoF1dBCF9AnChE+5fb4S/9bjSYRGFRGbuYxidOhOeLgc+e+c/I3ZXKNmSt8zMzF7f9/cDt7S0yNUlERGFgTAqIZDAGaYAXd1wP7sJvkNHlA6LSHbRsnl92LfH4g4LRETRR4iPg3ZVAcRZ0wG3B56qGvj22pQOi0h2PZvXA8CBD9ehsz3yRpplS94cDge2bNkS/L6vZG716tXIzs6Wq0siIgojIU4Lzd8thzg/E/B64fntFvh2Rde2QkQDcfnm9XsicPN6Weu85eTkQBAEFBUVobm5GYWFhXA6nairq0NVVRVMJhM2btwoV3eKY503IhqJJK8Pnudfh3/nfkAUoPnafVBlzVU6LCJZdbYfx0c1D8HnuYgZ1/8Q0xc/EvI+FSvSazab8eSTTwYOLgiQJAl6vR4VFRVYtWrVsI/d1taGioqKIT2/qqoKzc3NsFqtsNvtMJlMQz4WwOSNiEYuyeeHZ+Nb8NfvAQRAXXQ31EsWKh0WkayO73sFe9/5dwiiBkuW/xFJaTND2p/iOyy0tLTAZrPBYDAMa5eF0tJS2Gw25ObmorKyEiaTqVcNucEcp6SkBAaDAQDgdDpRWFiI+vp6tLS0QK/XD/qYTN6IaCST/BK8m7fB97edAAD1chPUtyi3tRCR3CRJws6tP8K5w+9gdOoMLFn+R4gqbcj6C3vy1traiunTp1+z3erVq/HMM0Pb/DU7Oxs5OTmDTt5qampgMBhgNPb+UHE6nUhJSYHJZEJtbe2g42HyRkQjnSRJ8L76Nnzv1AMA1PffAfWdSxSOikg+7k47/rZpJTxdDkxb9Ahm3vDDkPUV9u2xqqurr7kFlsvlwqZNm+TqcsBqa2uvSNwAQK/Xo7i4GBaLBU6nM+xxERFFO0EQoH7gTqjybwQAeF/7K7xbP4jY+lhEg6VNSMW82/8FAHB45x/gONmocEQyb491tfljTU1NyMjIUCRJ2rRpE/Lz8/t8rGf1a319fThDIiKKGYIgQHP3rVDfcysAwLv1A3hff4cJHMWMsdNvx6TZXwYgYc/b/wqft1vReGRN3mpra3uVC+lRVlYWvOSp0+nk7HJAcnJyYLf3vc1FTzKZmpoaxoiIiGKP2nQj1F9eCgDwvf0JvC9vh+RnAkexYdZN/4TkcfMx68Z/gkodp2gsarkOZDQa0dDQgPr6ejQ1NWHx4sVobW1FQUEBbDYbtm3bhry8PEV2WLjafLaeosF9XVYlIqLBUd+eA2jV8NZsg+99K+D2QL1yGQRR1rECorBTa0cj9yu/H/CmBCGNRa4D5eXlAQhsQL9+/Xps3LgRZrMZxcXFvS5JDmflaShUVVWhuLh4QG27u7vR3f35UGl7e3uowiIiilrqGxdD0GjgefFN+D7ZBcnjhebheyCoVEqHRjQskZC4ATJfNu2xatUqOBwOPPvss1esLG1qagpFl0NSWloKg8Ew4Fpv5eXl0Ol0wVt6enqIIyQiik6qnPnQfPMBQBThb9wLz+9egeT2KB0WUUwI2Tj2s88+C5vNho6Ojl73l5aWhqrLQbFaraiqqkJtbe2Aa7yVlZXB5XIFb0ePHg1tkEREUUy1aDY033kQUKvg33MI7mc3QbrQqXRYRFFv0JdNly1bNuC2bW1tqKmpCc4nczqdEbOqs7CwENu3bw8W7R2IuLg4xMUpO0mRiCiaqOZlQnhsJdy/2QKp9Tjcv3ge2uJCCKnhX7xGFCsGnbzV1dUhJydnSBP8IyV5y8/PR2VlJRcpEBGFgWhIh/YHX4O7qhrSGTu6f/48tMUFECeNUzo0oqg06OTNYDBg27ZtQ+7QZrMN+blyKCkpQWlpKUwmk6JxEBGNJOKEMYj74dcDCdypc3D/8gVovv0gVDOnKR0aUdQZ9Jy36urqYXU4lH1J5WI2m5Gfn39F4maz2WCxWBSKiohoZBD0SdD+4GEIhilAlxueqhr4GvcqHRZR1Bl08jaUUh+tra1obW0d8vMHyul09puE9exvWlBQcMVjVqt1UHPfiIhoaISEeGhLVkJcNBvw+eD542vwvqP8dBqiaCJbnbenn34a9fX1SE1NRX5+PpYvX47GxkaYTCakpqYiKysLgiBg48aNQ+7D6XT2u1MCEFiEYLFYUFlZ2at2m9VqRWVlJQoLC1FVVdXreG1tbbBYLGhoaBhyXERENHCCRg3NN+6HN2kUfO9b4X1lByRXB9T33QFBjIw6WkSRTNYdFvR6PVatWhW8r7CwEHl5ecHN6F0uF9atW4fHH398wMc1m82ora2FzWYL3rKzs2EwGFBUVNRrJC0/Px/19fXIycnpdYy8vLyrjspx1I2IKLwEUYT6wTwIuiR433gHvr/WQWo/D81D90BQs5gv0dUIkkw7B2/YsAGPPvpo8PvNmzdj5cqVcDgcSE5ODt6/fv36XgleNGtvb4dOp4PL5er1MxIR0cD56vfA89JbgN8PcdY0aL71FQjxLMtEI89A8wrZivR+MQesra2FwWBgUkNERFelypkPzaoVgFYD/4HDcP/qRUjt55UOiyhiyZa8paWl9freYrH0WY4jNTVVri6JiChGqGZnQPu9rwKjEyEdPwP3z5+H/0yb0mERRSTZkrfm5ubg142NjbDZbCgpKenVpqmpKWI2dSUiosgipk+A9odfgzBGD8nugvsXL8DfekLpsIgijmzJW0FBAVauXInVq1cjLy8PBQUFWLx4MQBgx44deOyxx5CXl8fFAURE1C9xTAq0P/gahPQJwIVOuJ95Cb49h5QOiyiiyLZgAQisJrVYLDAYDMjKygIAtLS04Gc/+xnOnTuH6dOnw2g0Yvny5XJ1qSguWCAiCg2p2w3P71+Ff58NEASoC++C+oZFSodFFFIDzStkTd6upbGxEQ0NDb1WpUYzJm9ERKEj+XzwVm+D75NdAAD1spuhuusmTr+hmBX21aYDkZmZidra2nB2SUREUUpQqaAu+hJUphsBAN6tH8BbvRWSz69wZETKkjV527FjB3JzczFz5kykpaX1uqlUKqSkpCA3N1fOLomIKIYJggDNPbdCvSIfEADfR5/C87uXIbk9SodGpBjZdlhobGxEQUEBiouLkZmZiYaGBmRnZyM1NRV2ux0NDQ3Iz8/HihUr5OqSiIhGCPXNWRCSRsHzp9fg39MM9zMbof275RBGJyodGlHYyTbnbfXq1Vi7di10Oh2AQDKXkpKC6dOnB9u0tLSgpaUFS5culaNLxXHOGxFRePltx+D+zRagswvCuFRoigshpuqUDotIFmGf82Y0GoOJGwDo9for9hLNyMiAzWaTq0siIhphRMMUaH/wMKBPgnTGDvfP/gT/8dNKh0UUVrIlb19c/ZORkYGGhga5Dk9ERAQAECeMQdwPvw5h4lig4wLcv3wRvgOHlQ6LKGxk39u0tbUVO3bsAADodDr85je/6dWOq02JiGi4BH0StN//KoTMdKDbDc/6avisnykdFlFYyDbnzeVyoby8HDU1NXA4HGhra4PT6YTBYEBmZiZMJhMsFgtycnLwzDPPyNGl4jjnjYhIWZLHC88Lb8C/cz8AQGW6Eeov3QxBDGslLCJZKFakt7GxEXq9HhkZGQAQ3ON0+/btyM/Px9atW+XsTlFM3oiIlCf5JXhfexu+d+oBAOKMqdB8/T4IyaMVjoxocCJyh4VYw+SNiChy+Bo+g6d6K+D2AEmjoP3G/RBnTFU6LKIBi8gdFgAE58MRERHJSZU9D9p//CaE8WmBhQzPbIR3+0eQ/ByjoNgS9uStoqIi3F0SEdEIIY5Pg/YfvgExZz4gSfC+8S48v90M6UKn0qERyUbWy6YbNmxAdXU17HZ7v22sVit8Pp9cXSqKl02JiCKTJEnwffQpvC9bAK8PSEmG9ptfhjhtotKhEfVroHmFbNtjPf3006isrITJZEJWVlafbSRJYpFeIiIKOUEQoL5xEcSpE+D53SuQ2pxw//J5qB+4E6pbjFfUJiWKJrIlb83NzTh06NA12zU2NsrVJRER0VWJk8dD+0+PwPPSW/DvOgDvy9vhtx2DpuhLEOLjlA6PaEhkm/OWnZ09oHaVlZVydUlERHRNQkIcNN/6MtRfWQqIIvw798P9f3+A/8QZpUMjGpKwL1joqf9GREQULoIgQH1bDrTfv7Qv6lkH3D/9E7wff6p0aESDJlvylpOTM6AyIEVFRXJ1SURENCji9EmI+6dHIM4xAF4vvBv/As+Lb0Jye5QOjWjAZJvzlpWVhaamJqxevRozZszoc9GC0+mE1WqVq0siIqJBE0YnQvPoCvi2fwTvX96Hr243/MdOQ/PIAxDHpSkdHtE1yZa8NTY2Ii8vD06n86rtuMKHiIiUJogC1Pk3Qpg+CZ4/vQ7p5Fm4/+8P0Kz8ElRZc5UOj+iqZLtsWlpaivXr18PhcMDv9/d766+MCBERUbipZk5D3I8egZCZDnR74Pnja/BsroXk9SodGlG/ZEvejEYjVqxYAZ1Od9V2nPNGRESRREgeDe1jRVCZbgAA+D5ohPsXL8BvdykcGVHfZEveZsyYMaB2TzzxhFxdEhERyUJQidDccxs0j64AEuMhHT0F9//8Dr49165fShRusiVvkiShvb39mu22bNkiV5dERESyUs3LRNw/PQJh6kSgsxue32yB57W/QvL5lQ6NKEi25G3VqlXYtGkTmpqartqORXqJiCiSCak6aL//MFS3BorP+97+BO5nXoLk6lA4MqIA2TamX7ZsGQCgvr4eTqcTBoMBer2+Vxun0wmbzcaN6YmIKCr4du6H56W3gG43MDoRmq/fD9WsaUqHRTFqoHmFbMlbamoqTCYTDAYD0tL6rpNz7tw5bNiwAW1tbXJ0qTgmb0REsc9/1h7Y3P7kWUAAVKYbA2VG1LJV2yICMPC8Qrb/eQaDAZs2bbpmO25MT0RE0UQcmwrt338d3pct8H28C77av8H/6QFoCu+CaEhXOjwagWQbeWtpaRnQvqUul+ua5USiBUfeiIhGFl/jXnhe3g6cvwgAUF1/HdT33wEhMV7hyCgWhP2y6UjE5I2IaOSRLnTC+/o78PVsaj86EZqvLIWYNZe7CNGwDDSvkG21KRER0UggjEqApuhL0H7/qxDGpQLnL8Lzp9fhqaqBv82pdHg0AjB5IyIiGgLRkA7t49+CetnNgEoF//4WuM2/hXfHx5BipKoCRSYmb0REREMkqNVQL7sZ2ie+BTEzHfB44X39Hbj/9w/wHz6pdHgUo5i8ERERDZM4Lg2a7z4E9UN3B7bXOnkW7p//EZ4tFkhd3UqHRzGGyRsREZEMBEGAeslCxD35KMSc+YAE+N63orviN/B9ekDp8CiGRFXyZjabUVpaGjHHISIi+iJhdCK0D98LzWMrIaTpAdd5eH73Z7h/uwWS49p7gBNdS8SXhy4tLYXNZkNubi4qKythMpkUPQ4REdFAqGZNh/jEt+G1/A2+HZ/Av/sQug8ehvru26C6JQuCGFXjJxRBZKvzVlZWhvLycjkO1a/s7Gzk5OQMe3N7uY7DOm9ERDQQ/pNn4aneCqn1BABASJ8AzcplECePVzgyiiRhr/NWVVWFnTt3ynU4IiKimCFOHAvt978GdUE+EK+FdPQU3P/3B3hefRtSt1vp8CjKyJa8ORwOrFmzBmVlZWhqapLrsERERDFBEAWob8oKLGhYNBvwS/D9tQ7d5t/Ct9emdHgURWRL3ioqKrB161aUl5ejra0NTz/9NDZs2CDX4YmIiGKCkDwa2ke+DM2jK4CUZMDRDs/6Grj/8Cqk9vNKh0dRQLYFC0888UTw67y8POTl5cHlcmH9+vVwuVwwmUxYvHixXN0poru7G93dn9fraW/nqiEiIhoa1bxMiJnp8P7lffjebYC/aR+697VAfd/tUN2wCILIfVKpbyFd6qLT6bBq1So8/vjjqK+vR25ublSPxpWXl0On0wVv6enpSodERERRTIjTQvPlpdD+4zcgTBkPdHXDW7MN7l+9AH/rcaXDowgV8nXKW7ZsQW5uLoqLi+FwOJCamhrqLkOmrKwMLpcreDt69KjSIRERUQwQp0yA9u+/AfWXlwJaDaSW43D//Hm4f/0SfAcPQ6bCEBQjZEvetmzZEvy6qakJq1evRlpaGgoKCpCdnY2GhgYcOnQIy5cvl6vLsIuLi0NycnKvGxERkRwElQj17TmIK/07qK5fCKhE+A8dgeeZjXD//Hn49hxiEkcAZJzz1lMEd+PGjbBarcjKysLatWuxatUqubogIiKKeUJKMjRFd0N9183wvv0JfB99CunwCXh+swXCpHFQm26AeN0sFvkdwWRL3pqbm1FaWopVq1ahqqoKWVlZch2aiIhoxBFSkqFZboI6/0Z4/1oH34eNkE6cgecPr0IYlwp13g0QjXMhqFRKh0phJlvyZjAY0NDQAJ1OJ9chiYiIRjwhaRQ0998B9dLr4XvfCu+7DZDO2OF58U0IWz+A6s4lUC1ZCEET8TtekkxkO9MFBQXBxG3Hjh2wWq2oq6uDwWDAkiVL8OCDD8rVFRER0YgjjEqAetnNUN2eA9+HTfD+tQ6S3QXv5lp4az+E+o4lUN24CEKcVulQKcRkS97Wrl2L1tZWFBcXw2KxAAD0ej2cTieAwH6iNTU1mDZtmlxdXsHpdKK+vp6bzhMRUcwS4uOgXno9VLcY4ft4F7xvfww4O+B99W14t38E9W3ZUN1ihJAQr3SoFCKyznYsKChAYWEhHA4H/H4/7HY7/H4/mpubUVhYiIKCgmEVtnU6nbDb7f0+XlhYiPz8fFRVVQ3rOERERJFO0GqgvtWIuB8XQ73ySxDG6IELnfC+9T66/+NZeN58F9L5i0qHSSEgSDKtO163bh1WrFiBjIyMftvYbDasX78e5eXlAz6u2WxGbW0tbDYbbLbA3m9GoxEGgwFFRUUoKCjo1ba8vBzbt2+H0Wgc8nEGqr29HTqdDi6Xi2VDiIhIUZLPD//OffBaPoJ06lzgTq0Gqhuug/qOJRD0ScoGSNc00LxCtuTt6aef7rVF1nDbRQMmb0REFGkkvwT/nkPwWv4G6eipwJ0qFVRLFkC19HqIaXpF46P+DTSvkG3Om16vH1A7QeBebURERKEiiAJUC2dCXDAD/gOt8Nb+DZLtGHx/2wnfx59CNM4LlBkZn6Z0qDREsiVvA03K2tra5OqSiIiI+iEIAlSzM6CanQG/7Si8tR/Bv78F/vo9cDfsgbhwFtR3Xg9h6gQOrEQZ2ZK3lJQUbNiwAY8++mi/bcrKypCZmSlXl0RERDQAoiEd2pJ0+I+ehNfyEfy7DsL/6QG4Pz0AYYweYtZcqLLmQpwwRulQaQBkm/MGACtXrkRLSwseeuih4A4LTqcTNpsNlZWVMBqN2Lhxo1zdKY5z3oiIKBr5T52Dd8fH8O/cD3i8wfuFCWOgypoDcfEciGNTFYxwZAr7goUeVVVVePLJJ+F0OiEIQnAT3YqKiphZqNCDyRsREUUzqdsN/55D8DXug39fC+DzBR8TpoyHKmsuVIvnQEjh77hwUCx569HS0gKbzQaDwXDV8iHRjMkbERHFCqmzC75dB+Fv3Af/wVbA/3l6IEyfDFXWHKgWzYaQPFq5IGOc4snbSMDkjYiIYpF0/iJ8n+6Hr3EfJNtRoCdTEASIM9IhLp4L1XWzIIxKUDTOWBOy5G3z5s1wOBxX3J+Tk4PFixcHv3e5XNi+fTtMJlPMJjZM3oiIKNZJrg74dl5K5A6f+PwBUYQ4ezpUi+dAXDgTQnycckHGiJAlby0tLSgtLcXmzZsBAMXFxTCZTMjPz7+io5aWFlgsFthsNpSUlGD69OmD/0kiGJM3IiIaSfxtTvib9sPXtBfS8TOfP6BWQZxrCKxYnWuAEKdVLsgoFtLLpj0JXEVFxYDnsz399NPIzs7G0qVLB9tdxGLyRkREI5X/dBv8Tfvga9wL6cxl+4VrNRDnZwYSuTkZENSyVSWLeSFN3oqKioZU8uPJJ5/Ej3/845hJdJi8ERHRSCdJEqSTZwMrVhv3QrK7Pn8wPg7iwplQzcmAmDGF+6teQ8iSt4FsQN8fl8uFtWvXDmpj+kjG5I2IiOhzkiRBOnIKvqa98DXtA1znez0upOogGKZANEyBaEiHMDaFuztcJmR7m9bV1eHxxx8fUlA6nQ42m21IzyUiIqLIJggChGkTIU6bCPX9d0JqPQbfpwfgtx2DdPwMJLsLkt0Ff/2ewBNGJ15K5AI3YdI4CKKo7A8RBXghmoiIiGQniAIEQzpEQzoAQOrqhr/1BPy2Y/DbjkI6chI4fxH+Tw/A/+mBwJPitBCnT/48mZs6EYKGqcoXDfoVGe7IGUfeiIiIRh4hPg6qORlQzQlMu5K8XkhHTl1K5o7B33oM6HLDv78F/v0tgSepVBCmTvx8dG76ZAgJLEky6ORNkiS0t7cPeY4XawITERGRoFYH578BgOT3Qzp59vNkznYM6LgAqeUYfC3H4NsOQBAgTBoLMeOyS60jcMeHQS9YePrpp2G324e06GDdunWQJClm9jjlggUiIqLQkCQJ0jln4BLrpWROanNe0U4YmxJYyTp9EsTxaRDGpkIYnRj+gGUQ0lIhqampePvtt7Fo0aIBP6exsREmkwktLS0xk+gweSMiIgofqf18r5E56eSZz7fuutyoBAjjUiGOTYUwLhVCT1KXpoegitwFESFbbQoAVVVVMBqNqKmpwYMPPnjN9ps3b8bKlStRXV3NJIeIiIiGREgeDdXiOVAtngMAkDq74G85HlzN6j/TBjjagQudkFqOw9dyvPcBVCKEMSmBRG5c6ucjdeNTISTEK/ATDc2QkreCggKUl5djxYoVyMnJQVFREfLy8mAwGJCcnIz29nbYbDZYLBZs3LgRVqsVa9euxfLly+WOn4iIiEYoISEeqnmZUM3LDN4nuT2QztohnQnc/GfaAl+fdQBuD6TTbZBOtwEAfJcfLGlU4BLsuLRAMjf20ohdSnLElS8Z0mXTHhaLBSUlJWhpaemzyJ4kSTAYDKisrEReXt6wAo1EvGxKREQUHSS/BLg64D9jh9ST0F1K7r5YTLgXtSowWjc+LTBaN2kcVItmhyTGkM55+6KamhpYLBbU19fD6XRCr9cjJycH+fn5WLFixXAPH7GYvBEREUU/qasb0lkHpDNtl5K7S7ezdsDba3wOwtSJiPuHb4QkjrAmbyMVkzciIqLYJfn9kBztl5K5Nkin7RDSdFDn3RCS/kK6YIGIiIgo1gmiCCFND6TpgbkGpcMJiqwZeERERER0VUzeiIiIiKIIkzciIiKiKMLkjYiIiCiKMHkjIiIiiiJM3oiIiIiiCJM3IiIioijC5I2IiIgoijB5IyIiIooiTN6IiIiIogiTNyIiIqIowuSNiIiIKIoweSMiIiKKIkzeiIiIiKIIkzciIiKiKMLkjYiIiCiKqJUOYDDMZjPa2tpQUVExpOdbLBbU1tYiMzMTTqcTALBmzRoZIyQiIiIKrYhP3kpLS2Gz2ZCbm4vKykqYTKYhHaempgYbN25EdXV18D6LxYL8/HzU1tbKFS4RERFRSAmSJElKBzFQ2dnZyMnJQWVl5aCe53Q6kZGRgZaWFuj1+iuOWVJSguLi4kHH097eDp1OB5fLheTk5EE/n4iIiKjHQPOKETHnbdOmTTAYDFckbgBQVFQ06GSQiIiISCkjInmrrq5Gampqn48ZDAZYrdbgHDgiIiKiSBbxc97kUF9fj5UrV/b5mMFgAADYbDYYjcYhHf/ChQtQqVRX3K9SqRAfH9+rXX9EUURCQsKQ2l68eBH9Xf0WBAGJiYlDatvZ2Qm/399vHKNGjRpS266uLvh8PlnaJiYmQhAEAEB3dze8Xq8sbRMSEiCKgb9t3G43PB6PLG3j4+OD/1cG09bj8cDtdvfbNi4uDmq1etBtvV4vuru7+22r1Wqh0WgG3dbn86Grq6vfthqNBlqtdtBt/X4/Ojs7ZWmrVqsRFxcHAJAkCRcvXpSl7WDe9/yM6LstPyP4GTFSPyOu9r7uRYoiRqNRKi4uHvTzAEhr1qzp87GGhgYJgFRdXX3N43R1dUkulyt4O3r0qASg39s999zT6/mJiYn9tr399tt7tR0zZky/bXNycnq1nTZtWr9t582b16vtvHnz+m07bdq0Xm1zcnL6bTtmzJhebW+//fZ+2yYmJvZqe88991z1dbtcQUHBVdueP38+2PaRRx65atszZ84E2373u9+9atuWlpZg28cff/yqbXfv3h1s+5Of/OSqbT/55JNgW7PZfNW2b7/9drDtL3/5y6u2ff3114Ntn3vuuau23bRpU7Dtpk2brtr2ueeeC7Z9/fXXr9r2l7/8ZbDt22+/fdW2ZrM52PaTTz65atuf/OQnwba7d+++atvHH3882LalpeWqbb/73e8G2545c+aqbR955JFg2/Pnz1+1bUFBQa//w1dry8+IwI2fEZ/f+BkRuI30zwiXyyVdzYi4bHo1fc2D6095eTl0Ol3wlp6eHrrAiIiIiPowIlabCoKANWvW9FkfzmazITMzE5WVlddccdrd3d1rSLi9vR3p6ek4ceJEn6tCeEmk77a8JMJLIiP1kshw2vIzYmht+RkRwM+IwbdV4jOivb0dkyZNuuZq0xEx5+1qehYq9Leg4XJxcXHBk3O5UaNG9fow6c9A2gyl7eUfpnK2vfzDX862l/+nlbNtf+dnuG21Wm3wza5UW41GE/zQk7OtWq0OfkjL2ValUg34//Bg2oqiGJK2giCEpC0Quvc9PyMG35afEYNvy8+IgHB9RlztD5HLjfjLpkRERETRZEQkbwaDATabrc/H7HZ7sA0RERFRpBsRyZvRaOy3jltPUjfUMiFERERE4TQikrf8/Px+R96am5uHvF8qERERUbjFVPLmdDphsViuuH/lypWw2+19JnA1NTUoKSkJR3hEREREwxZVyZvT6QzOUetLYWEh8vPzUVVV1et+vV6PiooKlJaW9rq/pqYGBoMBBQUFIYmXiIiISG4RXyrEbDajtrYWNpsteMvOzobBYEBRUVGvxCs/Px/19fXIycm54jjFxcUwGAwoLS1FZmZmcA5cbW1tuH4UIiIiomGLqiK9kaa9vR06ne6axfSIiIiIrmWgeUVUXTYlIiIiGumYvBERERFFESZvRERERFGEyRsRERFRFGHyRkRERBRFmLwRERERRZGIr/MWyXqqrLS3tyscCREREUW7nnziWlXcmLwNQ0dHBwAgPT1d4UiIiIgoVnR0dECn0/X7OIv0DoPf78eJEyeQlJQEQRBkO257ezvS09Nx9OhRFv9VEM+D8ngOIgPPg/J4DiJDqM+DJEno6OjApEmTIIr9z2zjyNswiKKIKVOmhOz4ycnJfJNGAJ4H5fEcRAaeB+XxHESGUJ6Hq4249eCCBSIiIqIowuSNiIiIKIoweYtAcXFx+MlPfoK4uDilQxnReB6Ux3MQGXgelMdzEBki5TxwwQIRERFRFOHIGxEREVEUYfJGREREFEWYvBERERFFESZvRERERFGERXojiMViQW1tLTIzM+F0OgEAa9asUTaoGFRSUhL812g0wul0or6+HpWVlSgrK4PRaOzVnudFHmazGW1tbaioqOi3zWBea56XobnWeeD7I7SqqqrQ3NwMq9UKu90Ok8nU77ng+yF0BnoeIvb9IFFEqK6ulgoKCnrdV1tbK5lMJoUiil0mk0kC0Oum1+ul2traK9ryvAzPmjVrpIKCAqmiokIyGAxScXFxv20H81rzvAzOYM4D3x+hs2bNGqm5uTn4vcPhkEwmk6TX6yWHw9GrLd8PoTOY8xCp7wcmbxHA4XD0+Z9GkiTJaDRKlZWV4Q8qhq1Zs0aqra2VKioqpIqKCqm6urrPdjwv8jIajf0mDYN5rXlehudq50GS+P4IlerqaqmhoeGK+x0OhwSg1y94vh9CZzDnQZIi9/3AOW8RYNOmTTAYDNDr9Vc8VlRUhMrKyvAHFeNMJhPWrFmDNWvWoKCgoM82PC/hM5jXmucl9Pj+kF9tbe0Vl9gAQK/Xo7i4GBaLJXiZje+H0BnMeegRie8HJm8RoLq6GqmpqX0+ZjAYYLVar/jPRKHH8xI+g3mteV4iA8/D4GzatAn5+fl9PpadnQ0AqK+vB8D3QygN5jwMRrjPA5O3CFBfXw+DwdDnYz3322y2cIZE4HkJp8G81jwvkYHnYXBycnJgt9v7fKznl3rPL3++H0JnMOdhMMJ9HrjaNAI4nc4+h1ovZ7PZ+hzqpaGx2WywWCzB75ubm1FWVtbrPPC8hM9gXmuel9Dj+0N+tbW1/T7W3NwMAMHXiu+H0BnMeegRie8HJm8R7lr/GWjwbDYbrFYriouLg/dZrVZkZ2ejoaFhQK85z0v4DOa15nkZPr4/wq+qqqrX6301fD+ETl/nIVLfD7xsGiX6G+alwauurr5i0qnRaITRaMSqVasGdSyel/AZzGvN8zJ0fH+EV2lpKQwGw1XrH/aF7wd59XceIvX9wOQtwg3nGjwNTm5uLmpqagbUluclfAbzWvO8hA7fH/KzWq2oqqpCbW3tgEdn+H6Q31DOg9LvByZvRJf0TCq1Wq0KR0IUefj+kF9hYSG2b9/e70R3Co+hnAel3w9M3iKAwWDodxVKzzAr39zyKCkpQWlpaZ+P9fzFdflrzvMSHoN5rXleQofvj/DJz89HZWVlnxPY+X4In6udh0h+PzB5iwA9K4b60vOfgSuF5LFp06Z+32A99+fk5ADgeQmnwbzWPC+hw/dHePQkBSaTqc/H+X4Ij2udh0h+PzB5iwD5+fn9/gdpbm7u9z8WDV5xcTGqq6v7fKy2trZXhWyel/AZzGvN8xI6fH+EntlsRn5+/hWvz+XlKPh+CL2BnIeIfj/IutkWDUnPnmiXb5Tbw2Aw9LuXGg3etfa1u/y15nmR10D2Nh3Ia83zMjxXOw98f4RWdXV1v69LdXV18LXk+yG0BnoeIvn9wOQtQlRWVkoFBQW97quurr5ik1wavuLi4ivekP39QuN5kY/BYLjitbzcYF5rnpehu9Z54PsjNBoaGiSTySRVVlb2ulVUVEhr1qyRjEZjr/Z8P4TGYM9DpL4fBEmSJHnH8mioLBYLamtrkZmZGbx2vmbNGmWDilFmsxltbW1wOp2w2+0oKirqd8NhnpehM5vNqK2thc1m6zXvw2Aw9PmaD+a15nkZuMGeB74/5JeSknLVvS0NBkOwwn8Pvh/kN5TzEInvByZvRERERFGECxaIiIiIogiTNyIiIqIowuSNiIiIKIoweSMiIiKKIkzeiIiIiKIIkzciIiKiKMLkjYiIiCiKMHkjIiIiiiJM3oiIiIiiCJM3IhqxeraKoivxtSGKXEzeiGhEKi0tRWpqqtJhRCyn04mqqiqlwyCiPnBvUyKKGlVVVcFNo9PS0oa84XNJSQlKS0thMBjkDC/mVFVVITU1td9NuIlIGRx5I6KoUFhYiObmZlRUVKCiogK1tbWwWCyDPk5NTQ30en3MJm6ZmZkoKSmR5VjFxcWorKyE0+mU5XhEJA8mb0QU8UpKSmCz2VBRURG8z2g0orKyctDHKi8v73WcWKTX62U7VkVFBVatWiXb8Yho+NRKB0BEdDUWiwVVVVVoaGjodX9aWtqg52TV1NQgJydHzvAiTs9lZbkYjUZYrVY4nU5Zk0IiGjqOvBFRRCspKYHRaITRaOx1f1tb26Av51VWVqKwsFDG6EaGgoICLl4giiBM3ogoYlksFthsNpSVlV3x2GBLWTidTtTX18NkMskV3ohRUlIypEvURBQavGxKRBGrJ2Hoa7WjxWIZ1GU8i8VyzUumTqcTmzZtCn7f0NAQHPnrYbPZUFhYCJvNhpUrV6KioiI4KlVbW4va2tpex6ypqUFdXR3S0tLQ1taGzMxMFBcXX3GsnJwc1NbWBo/V3NwMq9WKioqK4KXL+vr6YFyZmZlXrLbNzs4OXt7sucx8tT6cTifq6upQUVFx1QUcBoMBNpuNl06JIoVERBSBHA6HBEAymUyDeqw/FRUV0po1a67a5ouPOxwOSa/XS7W1tVe0NZlMUkFBgVRRUSFJkiTV1tZKAKTm5uZexysoKLjimF/sp6CgQDKZTFJlZaXkcDiC91dXV0t6vV5qaGi4IgaDwSBVVlZeEVdBQYFkNBr7vP9qfVyL0Wjs83UgovDjZVMiikg9o0M2mw35+fm9bnl5eQBwxTy4q2lubkZmZma/j1utVtTU1PS6HKvX61FcXIzS0tIr2veMhvVchjWZTHA4HMERLIvFArPZjPXr1/d6ns1mu6Ifg8GA+vp65OTk9BrZMplMcDqdqKysvOJyr8lkQnV19RVx5ebm9vnzXasPq9Xazyvz+fNZMoQoMvCyKRFFpLq6OgCBS5FfvKRXUlICq9WKoqKiAR/Pbrdf9XG9Xg+73Q6bzdarv8zMTNTU1PR7zMsTyMuTotLSUhQUFFxxmdFut18RS1paGpxO5xXJaM9z+0o6e+IdqGv1MZBjDaY/IgodJm9EFJGsVmu/xXQ3bdrU5wrUq3E6nVfdDstgMMDhcAS/75nj1dDQ0G/ScrV5YpePyl2uZ4RuMMcazM95NcMpTJyamip7GRIiGhpeNiWiiNQzwf6LemqO9bUCdbicTidKS0tRUlISXBCRnZ3db/v+ksGeS6JpaWkD7jscCwGG28dgfh4iCh0mb0QUsfoaKSovL4derx/0fpvXusxos9mQkZGBzMxMVFZWori4GAaDYUib1/fE3dbWNujnRiq73R6zW4oRRRsmb0QUkfR6/RUjRT2T/b+4CGAgrjXhvqSkBAaDIVjGo8cXE76B7qfaU14jVrBMCFHkYPJGRBGpr0umJSUlKCgoGPSoGxCY9H+1OVsWi6XPOWoNDQ29kr6BJmQVFRWoqanpM2HsSUKjyRcXchCRcpi8EVFEKi0t7VW+wmw2A0Cf5TEGIicnJ1jkti8mk+mKUbWeMiUAguU0epJKp9N51cuwBQUFKC4u7nM7rpqaml4J6LW2+hpsiY6+2g+3D142JYocgiRJktJBEBH1xWw2B+eNpaWlXbGjwGClpKSgpaWl38t/JSUlsNvtwYTNYDDAZDLBbDajrq4O+fn5MJlMKCkpQX19PZxOJ0wmE4xGIyoqKvo8Zk1NDWpra5GZmQmDwQC73R68NOt0OlFYWNjrWD2ji2azGRs3boTVaoXBYIDRaER1dTVsNtsV/ZeWliInJ+eKY/XsnDDYPvr6GTZu3DjkxJmI5MXkjYhGjNLS0l7bU9HAFBYWoqSkhPvCEkUIJm9ENGL07PPZs+8nDcy15gsSUXhxzhsRjRgGgwE5OTnX3AqKPmc2m/u9JExEyuDIGxGNKD3zzGpra5UOJeLxtSKKTBx5I6IRRa/Xo7S0NLh6lfpXWlrKRQpEEYgjb0Q0IvVcOpVr39BYU1NTA5PJxMK8RBGIyRsRERFRFOFlUyIiIqIowuSNiIiIKIoweSMiIiKKIkzeiIiIiKIIkzciIiKiKMLkjYiIiCiKMHkjIiIiiiJM3oiIiIiiyP8HGKryTODMyi4AAAAASUVORK5CYII=", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "theta = np.linspace(1,250,20)\n", + "plt.axhline(y=1, color='k', ls='--')\n", + "plt.plot(theta,np.diag(cov_masked)[:20]/np.diag(cov)[:20], label=r'$\\xi_+$')\n", + "plt.plot(theta,np.diag(cov_masked)[20:]/np.diag(cov)[20:], label=r'$\\xi_-$')\n", + "\n", + "plt.xlabel(r'$\\theta$ (arcmin)')\n", + "plt.ylabel('Cov masked / Cov unmasked')\n", + "plt.legend(fontsize=20)\n", + "plt.savefig(f'{curr_dir}/../Plots/covmat_masked_unmasked_ratio_diag.pdf', bbox_inches='tight')" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "my_env", + "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.10.13" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/cosmo_inference/notebooks/2D_cosmic_shear_configuration_plots/nonlin_k_analysis.ipynb b/cosmo_inference/notebooks/2D_cosmic_shear_configuration_plots/nonlin_k_analysis.ipynb new file mode 100644 index 00000000..5c047ec4 --- /dev/null +++ b/cosmo_inference/notebooks/2D_cosmic_shear_configuration_plots/nonlin_k_analysis.ipynb @@ -0,0 +1,171 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Nonlinear $k$ contributions\n", + "\n", + "This notebook plots the 2D heatmap of ratio of scale contributions to the $\\xi_\\pm$ 2PCF given angular scale $\\theta$ and wavenumber $k$." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "import os\n", + "import matplotlib.pylab as plt\n", + "import seaborn as sns\n", + "plt.style.use(\n", + " \"/home/guerrini/matplotlib_config/paper.mplstyle\"\n", + ")\n", + "\n", + "plt.rcParams['text.usetex'] = True\n", + "\n", + "plt.rcParams.update({\n", + " \"font.size\": 20, \n", + " \"axes.titlesize\": 21,\n", + " \"axes.labelsize\": 20,\n", + " \"xtick.labelsize\": 20,\n", + " \"ytick.labelsize\": 20,\n", + " \"legend.fontsize\": 20,\n", + " \"figure.titlesize\": 21,\n", + "})\n", + "sns.set_palette(\"husl\")\n", + "\n", + "blind = 'B'\n", + "ver = 'v1.4.6.3'\n", + "\n", + "%matplotlib inline\n", + "\n", + "data_dir = f'/n23data1/n06data/lgoh/scratch/UNIONS/cosmo_inference/data/'\n", + "curr_dir = os.getcwd()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Plotting from script" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Read the 2D array from the text file\n", + "\n", + "file_headers = [ \"xip_%s_%s\" % (ver, blind) , \"xim_%s_%s\" % (ver, blind) ]\n", + "\n", + "for f in file_headers:\n", + " \n", + " xis = np.loadtxt(data_dir + f'theta_k_{f}.txt')\n", + " xis_reshaped = xis.reshape(-1,201)\n", + " sorted_xis = xis_reshaped[np.argsort(xis_reshaped[:, 0])]\n", + " \n", + " np.savetxt(data_dir + f'theta_k_{f}_sorted.txt', sorted_xis)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "fig, axs = plt.subplots(2, 1, figsize=(8,10))\n", + "\n", + "# --- k grid ---\n", + "h = 0.6766\n", + "k_plot = np.logspace(-4, 2, 200)\n", + "\n", + "file_header = \"%s_%s\" % (ver, blind)\n", + "\n", + "xi_thetas = np.loadtxt(data_dir + f'theta_k_xip_{file_header}_sorted.txt')\n", + "thetas = xi_thetas[:,0]\n", + "xis = xi_thetas[:,1:]\n", + "\n", + "# normalise\n", + "xi_plot = xis / np.max(xis, axis=1, keepdims=True)\n", + "\n", + "T, K = np.meshgrid(thetas, k_plot)\n", + "\n", + "axs[0].contour(T, K, xi_plot.T, levels=[0.9], colors='red', linewidths=1.7)\n", + "pcm = axs[0].pcolormesh(T, K, xi_plot.T, shading='auto', cmap='viridis')\n", + "pcm.set_rasterized(True)\n", + "\n", + "axs[0].axvline(5, color='k', ls='dashed',lw=1.2)\n", + "axs[0].axvline(12, color='white', ls='dashed',lw=1.6)\n", + "axs[0].axhline(1, color='k', ls='dashed',lw=1.2) # converted to h/Mpc space if needed\n", + "axs[0].axhline(0.425, color='white', ls='dashed',lw=1.6)\n", + "\n", + "axs[0].set_yscale('log')\n", + "axs[0].set_xlabel(r'$\\theta\\ \\mathrm{(arcmin)}$')\n", + "axs[0].set_ylabel(r'$k\\ (h$ Mpc$^{-1})$')\n", + "\n", + "axs[0].set_title(r'$\\xi_+$')\n", + "\n", + "xi_thetas = np.loadtxt(data_dir + f'theta_k_xim_{file_header}_sorted.txt')\n", + "thetas = xi_thetas[:,0]\n", + "xis = xi_thetas[:,1:]\n", + "\n", + "xi_plot = xis / np.max(xis, axis=1, keepdims=True)\n", + "\n", + "T, K = np.meshgrid(thetas, k_plot)\n", + "\n", + "axs[1].contour(T, K, xi_plot.T, levels=[0.9], colors='red', linewidths=1.7)\n", + "pcm = axs[1].pcolormesh(T, K, xi_plot.T, shading='nearest', cmap='viridis')\n", + "pcm.set_rasterized(True)\n", + "\n", + "axs[1].axvline(12, color='white', ls='dashed', lw=1.6)\n", + "axs[1].axhline(2.85, color='white', ls='dashed', lw=1.6)\n", + "\n", + "\n", + "axs[1].set_yscale('log')\n", + "axs[1].set_xlabel(r'$\\theta\\ \\mathrm{(arcmin)}$')\n", + "axs[1].set_ylabel(r'$k\\ (h$ Mpc$^{-1})$')\n", + "axs[1].set_title(r'$\\xi_-$')\n", + "\n", + "\n", + "fig.tight_layout()\n", + "\n", + "cbar_ax = fig.add_axes([0.99, 0.15, 0.02, 0.7])\n", + "cbar = fig.colorbar(pcm, cax=cbar_ax)\n", + "\n", + "fig.savefig(curr_dir + f'/../Plots/theta_k_xip_xim_{ver}_{blind}.pdf', bbox_inches='tight')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "my_env", + "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.10.13" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/cosmo_inference/notebooks/2D_cosmic_shear_paper_plots/ psf_leakage.ipynb b/cosmo_inference/notebooks/2D_cosmic_shear_paper_plots/ psf_leakage.ipynb deleted file mode 100644 index 20f4a5a0..00000000 --- a/cosmo_inference/notebooks/2D_cosmic_shear_paper_plots/ psf_leakage.ipynb +++ /dev/null @@ -1,248 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## PSF Leakage Plots\n", - "\n", - "This notebook creates all the plots of the PSF leakage: the scale-dependent $\\alpha$ parameter, $\\rho$ and $\\tau$ statistics (from Guerrini et al. 2024) as well as the covariance matrix of the $\\tau_0$ ad $\\tau_2$ data vectors." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "import matplotlib\n", - "from astropy.io import fits\n", - "import matplotlib.pyplot as plt\n", - "import uncertainties\n", - "import yaml\n", - "import os\n", - "import numpy as np\n", - "\n", - "plt.rcParams.update({'font.size': 25,'figure.figsize':[12,7]})\n", - "plt.rcParams.update({\"text.usetex\": True})\n", - "plt.rc('mathtext', fontset='stix')\n", - "plt.rc('font', family='serif')\n", - "\n", - "# Define path to data files (NOTE: YOU MUST HAVE RAN THE cosmo_val.py PIPELINE!)\n", - "cosmoval_data_dir = \"/n23data1/n06data/lgoh/scratch/UNIONS/sp_validation/notebooks/cosmo_val/output\"\n", - "ver = \"SP_v1.4.5\"\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Plot the $\\alpha(\\theta)$ leakage" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Read in the text file of the 2PCFs\n", - "\n", - "alpha_fname = f\"{cosmoval_data_dir}/leakage_{ver}/alpha_leakage.txt\"\n", - "print(f\"Reading xi_sys's from {alpha_fname}\")\n", - "\n", - "alphas = np.loadtxt(alpha_fname)\n", - "theta = alphas[:,0]\n", - "alpha = alphas[:,1]\n", - "var_alpha = alphas[:,2]\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "\n", - "# Plot the xi_+sys\n", - "ax1 = plt.subplot(111)\n", - "ax1.tick_params(axis='both', which='both', direction='in', length=6, width=1,\n", - " top=True, bottom=True, left=True, right=True)\n", - "ax1.yaxis.minorticks_on()\n", - "\n", - "ax1.errorbar(theta, alpha, yerr=var_alpha, \n", - " fmt='o', markersize=4, capsize=2, capthick=1.5, ls = 'solid', lw=1.8,\n", - " color='darkviolet')\n", - "ax1.axhline(0,ls='dashed',lw=1, color='grey')\n", - "ax1.text(0.85, 0.15, r'$1-1$', transform=ax1.transAxes,\n", - " bbox=dict(facecolor='white', edgecolor='black', boxstyle='round', pad=0.5))\n", - "ax1.set_xscale('log')\n", - "ax1.set_xlabel(r'$\\theta$ [arcmin]')\n", - "ax1.set_ylabel(r'$\\alpha(\\theta)$')\n", - "# plt.savefig('plots/alpha_sys_%s.pdf' %ver,bbox_inches='tight')\n", - "plt.show()\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Plot the $\\tau(\\theta)$ statistics" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "tau_stats_fname = f\"{cosmoval_data_dir}/rho_tau_stats/tau_stats_{ver}.fits\"\n", - "print(f\"Reading tau stats from {tau_stats_fname}\")\n", - "tau_stats_hdu = fits.open(tau_stats_fname)\n", - "\n", - "theta = tau_stats_hdu[1].data['theta']\n", - "\n", - "tau_0_p = tau_stats_hdu[1].data['tau_0_p']\n", - "vartau_0_p = tau_stats_hdu[1].data['vartau_0_p']\n", - "\n", - "tau_2_p = tau_stats_hdu[1].data['tau_2_p']\n", - "vartau_2_p = tau_stats_hdu[1].data['vartau_2_p']" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "#Plot the xi_plus\n", - "ax1 = plt.subplot(111)\n", - "ax1.tick_params(axis='both', which='both', direction='in', length=6, width=1,\n", - " top=True, bottom=True, left=True, right=True)\n", - "ax1.yaxis.minorticks_on()\n", - "\n", - "# ax1.errorbar(theta, tau_0_p*1e4, yerr=np.sqrt(vartau_0_p)*1e4, \n", - "# fmt='o', markersize=6, capsize=2, capthick=1.5, ls = 'solid', lw=1.8,\n", - "# color='royalblue')\n", - "ax1.plot(theta, tau_0_p*1e4, marker='o', markersize=4, ls = 'solid', lw=1.8, color=\"royalblue\")\n", - "ax1.fill_between(theta, (tau_0_p-np.sqrt(vartau_0_p))*1e4, (tau_0_p+np.sqrt(vartau_0_p))*1e4, color=\"powderblue\", alpha=0.7)\n", - "ax1.text(0.85 , 0.88, r'$1-1$', transform=ax1.transAxes,\n", - " bbox=dict(facecolor='white', edgecolor='black', boxstyle='round', pad=0.5))\n", - "ax1.axhline(0,ls='dashed',lw=1.5, color='grey')\n", - "# ax1.axvspan(0,10,color='gray', alpha=0.3)\n", - "# ax1.axvspan(150,200,color='gray', alpha=0.3)\n", - "ax1.set_xscale('log')\n", - "ax1.set_xlabel(r'$\\theta$ [arcmin]')\n", - "ax1.set_ylabel(r'$\\tau_{0,+}\\times 10^4$')\n", - "# plt.savefig('plots/tau0_%s.pdf' %ver,bbox_inches='tight')\n", - "plt.show()\n", - "\n", - "# Plot the xi_minus\n", - "ax2 = plt.subplot(111)\n", - "ax2.tick_params(axis='both', which='both', direction='in', length=6, width=1,\n", - " top=True, bottom=True, left=True, right=True)\n", - "ax2.yaxis.minorticks_on()\n", - "\n", - "# ax2.errorbar(theta, tau_2_p*1e4, yerr=np.sqrt(vartau_2_p)*1e4, \n", - "# fmt='o', markersize=6, capsize=2, capthick=1.5, ls = 'solid', lw=1.8,\n", - "# color='orangered')\n", - "ax2.plot(theta, tau_2_p*1e4, marker='o', markersize=4, ls = 'solid', lw=1.8, color=\"orangered\")\n", - "ax2.fill_between(theta, (tau_2_p-np.sqrt(vartau_2_p))*1e4, (tau_2_p+np.sqrt(vartau_2_p))*1e4, color=\"pink\", alpha=0.7)\n", - "ax2.text(0.85, 0.88, r'$1-1$', transform=ax2.transAxes,\n", - " bbox=dict(facecolor='white', edgecolor='black', boxstyle='round', pad=0.5))\n", - "ax2.axhline(0,ls='dashed',lw=1.5, color='grey')\n", - "# ax2.axvspan(0,10,color='gray', alpha=0.3)\n", - "# ax2.axvspan(150,200,color='gray', alpha=0.3)\n", - "ax2.set_xscale('log')\n", - "ax2.set_xlabel(r'$\\theta$ [arcmin]')\n", - "ax2.set_ylabel(r'$\\tau_{2,+}\\times 10^4$')\n", - "# plt.savefig('plots/tau2_%s.pdf' %ver,bbox_inches='tight')\n", - "plt.show()\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Plot the $\\tau$ covariance matrix" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "tau_covmat_file = f\"{cosmoval_data_dir}/rho_tau_stats/cov_tau_{ver}_th.npy\"\n", - "print(f\"Reading tau covmat from {tau_covmat_file}\")\n", - "tau_cov = np.load(tau_covmat_file)\n", - "ndata = len(tau_cov[0])\n", - "tau_cov = tau_cov[:int(2*ndata/3),:int(2*ndata/3)]\n", - "cmap = 'coolwarm'" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "ndata = len(tau_cov[0])\n", - "pp_norm = np.zeros((ndata,ndata))\n", - "for i in range(ndata):\n", - " for j in range(ndata):\n", - " pp_norm[i][j] = tau_cov[i][j]/ np.sqrt(tau_cov[i][i]*tau_cov[j][j])\n", - "\n", - "fig = plt.figure()\n", - "ax = fig.add_subplot(1, 1, 1) \n", - "extent = (0, ndata, ndata, 0)\n", - "im3 = ax.imshow(pp_norm, cmap=cmap, vmin=-1, vmax=1, extent=extent)\n", - "\n", - "plt.axvline(x=int(ndata/2),color='black',linewidth=1.0)\n", - "plt.axhline(y=int(ndata/2),color='black',linewidth=1.0)\n", - "\n", - "fig.colorbar(im3, orientation='vertical')\n", - "ticks = np.arange(0,ndata+10,10)\n", - "tick_labels = np.array([0,10,0,10,20])\n", - "ax.set_xticks(ticks,labels= tick_labels)\n", - "ax.set_yticks(ticks,labels= tick_labels)\n", - "ax.text(int(ndata/4), ndata+5, r'$\\tau_{0,+}(\\theta)$')\n", - "ax.text(3*int(ndata/4), ndata+5, r'$\\tau_{2,+}(\\theta)$')\n", - "ax.text(-11, int(ndata/4), r'$\\tau_{0,+}(\\theta)$')\n", - "ax.text(-11, 3*int(ndata/4), r'$\\tau_{2,+}(\\theta)$')\n", - "\n", - "# plt.savefig(\"plots/tau_covmat.pdf\", bbox_inches='tight')\n", - "plt.show()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "sp-validation", - "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.9.21" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/cosmo_inference/notebooks/2D_cosmic_shear_paper_plots/.gitignore b/cosmo_inference/notebooks/2D_cosmic_shear_paper_plots/.gitignore deleted file mode 100644 index d7bb7cd2..00000000 --- a/cosmo_inference/notebooks/2D_cosmic_shear_paper_plots/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -results/* -plots/* -.snakemake/* \ No newline at end of file diff --git a/cosmo_inference/notebooks/2D_cosmic_shear_paper_plots/2025_10_13_plot_data_vectors.py b/cosmo_inference/notebooks/2D_cosmic_shear_paper_plots/2025_10_13_plot_data_vectors.py deleted file mode 100644 index e69de29b..00000000 diff --git a/cosmo_inference/notebooks/2D_cosmic_shear_paper_plots/2025_10_28_plot_whisker_config_space.ipynb b/cosmo_inference/notebooks/2D_cosmic_shear_paper_plots/2025_10_28_plot_whisker_config_space.ipynb deleted file mode 100644 index 669ae7f2..00000000 --- a/cosmo_inference/notebooks/2D_cosmic_shear_paper_plots/2025_10_28_plot_whisker_config_space.ipynb +++ /dev/null @@ -1,490 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 8, - "id": "889d7da8", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "['SP_v1.4.6_leak_corr_A_10_80', 'SP_v1.4.6_leak_corr_B_10_80', 'SP_v1.4.6_leak_corr_C_10_80', 'SP_v1.4.6_leak_corr_A_fid_cell', 'SP_v1.4.6_leak_corr_A_4_80', 'SP_v1.4.6_leak_corr_A_5_80', 'SP_v1.4.6_leak_corr_A_7_80', 'SP_v1.4.6_leak_corr_A_11_80', 'SP_v1.4.6_leak_corr_A_10_80_no_bar', 'SP_v1.4.6_leak_corr_A_10_80_halofit', 'SP_v1.4.6_no_leak_corr_A_10_80']\n" - ] - } - ], - "source": [ - "from getdist import plots, loadMCSamples\n", - "import numpy as np\n", - "import matplotlib.pyplot as plt\n", - "import seaborn as sns\n", - "\n", - "plt.style.use(\n", - " \"/home/guerrini/matplotlib_config/paper.mplstyle\"\n", - ")\n", - "\n", - "plt.rc('text', usetex=True)\n", - "\n", - "sns.set_palette(\"husl\")\n", - "\n", - "g = plots.get_subplot_plotter(width_inch=30)\n", - "g.settings.axes_fontsize=60\n", - "g.settings.axes_labelsize=60\n", - "g.settings.alpha_filled_add = 0.7\n", - "g.settings.legend_fontsize = 60\n", - "\n", - "%matplotlib inline\n", - "\n", - "#SPECIFY DATA DIRECTORY AND DESIRED CHAINS TO ANALYSE\n", - "root_dir = \"/n09data/guerrini/output_chains/\"\n", - "\n", - "roots = [\n", - " \"SP_v1.4.6_leak_corr_A_10_80\",\n", - " \"SP_v1.4.6_leak_corr_B_10_80\",\n", - " \"SP_v1.4.6_leak_corr_C_10_80\",\n", - " \"SP_v1.4.6_leak_corr_A_fid_cell\",\n", - " \"SP_v1.4.6_leak_corr_A_4_80\",\n", - " \"SP_v1.4.6_leak_corr_A_5_80\",\n", - " \"SP_v1.4.6_leak_corr_A_7_80\",\n", - " \"SP_v1.4.6_leak_corr_A_11_80\",\n", - " \"SP_v1.4.6_leak_corr_A_10_80_no_bar\",\n", - " \"SP_v1.4.6_leak_corr_A_10_80_halofit\",\n", - " \"SP_v1.4.6_no_leak_corr_A_10_80\"\n", - "]\n", - "\n", - "legend_labels = [\n", - " r\"UNIONS $\\xi_\\pm(\\vartheta)$, Blind A\",\n", - " r\"UNIONS $\\xi_\\pm(\\vartheta)$, Blind B\",\n", - " r\"UNIONS $\\xi_\\pm(\\vartheta)$, Blind C\",\n", - " r\"UNIONS $C_\\ell$, Blind A\",\n", - " r\"$\\vartheta \\in [4',80']$\",\n", - " r\"$\\vartheta \\in [5',80']$\",\n", - " r\"$\\vartheta \\in [7',80']$\",\n", - " r\"$\\vartheta \\in [11',80']$\",\n", - " r\"No baryons\",\n", - " r\"Halofit\",\n", - " r\"No leakage correction\"\n", - "]\n", - "\n", - "colours = [\n", - " \"darkorange\",\n", - " \"crimson\",\n", - " \"forestgreen\",\n", - " \"royalblue\",\n", - " \"darkorange\",\n", - " \"darkorange\",\n", - " \"darkorange\",\n", - " \"darkorange\",\n", - " \"darkorange\",\n", - " \"darkorange\",\n", - " \"darkorange\"\n", - "]\n", - "\n", - "print(roots)" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "id": "694ae47f", - "metadata": {}, - "outputs": [], - "source": [ - "# MAKE PARAMNAMES FILE\n", - "\n", - "for root in roots:\n", - " with open(root_dir + '{}/samples_{}.txt'.format('/'+root ,root), \"r\") as file:\n", - " params = file.readline()[1:].split('\\t')[:-4]\n", - " file.close()\n", - " \n", - " with open(root_dir + '{}/getdist_{}.paramnames'.format('/'+root, root), \"w\") as file:\n", - " for i in range(len(params)):\n", - " if len(params[i].split('--')) > 1:\n", - " file.write(params[i].split('--')[1] + '\\n')\n", - " else:\n", - " file.write(params[i].split('--')[0] + '\\n')\n", - " file.close()" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "id": "45061659", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "1618\n", - "/n09data/guerrini/output_chains/SP_v1.4.6_leak_corr_A_10_80/getdist_SP_v1.4.6_leak_corr_A_10_80.txt\n", - "Removed no burn in\n", - "1612\n", - "/n09data/guerrini/output_chains/SP_v1.4.6_leak_corr_B_10_80/getdist_SP_v1.4.6_leak_corr_B_10_80.txt\n", - "Removed no burn in\n", - "1608\n", - "/n09data/guerrini/output_chains/SP_v1.4.6_leak_corr_C_10_80/getdist_SP_v1.4.6_leak_corr_C_10_80.txt\n", - "Removed no burn in\n", - "1728\n", - "/n09data/guerrini/output_chains/SP_v1.4.6_leak_corr_A_fid_cell/getdist_SP_v1.4.6_leak_corr_A_fid_cell.txt\n", - "Removed no burn in\n", - "1931\n", - "/n09data/guerrini/output_chains/SP_v1.4.6_leak_corr_A_4_80/getdist_SP_v1.4.6_leak_corr_A_4_80.txt\n", - "Removed no burn in\n", - "1876\n", - "/n09data/guerrini/output_chains/SP_v1.4.6_leak_corr_A_5_80/getdist_SP_v1.4.6_leak_corr_A_5_80.txt\n", - "Removed no burn in\n", - "1739\n", - "/n09data/guerrini/output_chains/SP_v1.4.6_leak_corr_A_7_80/getdist_SP_v1.4.6_leak_corr_A_7_80.txt\n", - "Removed no burn in\n", - "1579\n", - "/n09data/guerrini/output_chains/SP_v1.4.6_leak_corr_A_11_80/getdist_SP_v1.4.6_leak_corr_A_11_80.txt\n", - "Removed no burn in\n", - "1623\n", - "/n09data/guerrini/output_chains/SP_v1.4.6_leak_corr_A_10_80_no_bar/getdist_SP_v1.4.6_leak_corr_A_10_80_no_bar.txt\n", - "Removed no burn in\n", - "1636\n", - "/n09data/guerrini/output_chains/SP_v1.4.6_leak_corr_A_10_80_halofit/getdist_SP_v1.4.6_leak_corr_A_10_80_halofit.txt\n", - "Removed no burn in\n", - "1590\n", - "/n09data/guerrini/output_chains/SP_v1.4.6_no_leak_corr_A_10_80/getdist_SP_v1.4.6_no_leak_corr_A_10_80.txt\n", - "Removed no burn in\n" - ] - } - ], - "source": [ - "#READ CHAIN\n", - "\n", - "chains=[]\n", - "\n", - "for root in roots:\n", - "\n", - " samples = np.loadtxt(root_dir + '{}/samples_{}.txt'.format(root,root))\n", - " print(len(samples))\n", - " if 'nautilus' in root:\n", - " samples = np.column_stack((np.exp(samples[:,-3]),samples[:,-1]-samples[:,-2],samples[:,0:-3]))\n", - " else:\n", - " samples = np.column_stack((samples[:,-1],samples[:,-3],samples[:,0:-4]))\n", - " np.savetxt(root_dir + '{}/getdist_{}.txt'.format(root,root), samples)\n", - " \n", - " chain = g.samples_for_root(root_dir + '{}/getdist_{}'.format(root,root),\n", - " cache=False,\n", - " settings={'ignore_rows':0,\n", - " 'smooth_scale_2D':0.5,\n", - " 'smooth_scale_1D':0.5})\n", - "\n", - " chains.append(chain)" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "id": "e57927c8", - "metadata": {}, - "outputs": [], - "source": [ - "name_list = ['OMEGA_M','ombh2','h0','n_s','SIGMA_8','s_8_input','a','m1','bias_1']\n", - "label_list = ['\\Omega_m', '\\omega_b h^2', 'h_0', 'n_s', '\\sigma_8', 'S_8', 'A_{IA}', 'm_1', '\\Delta z_1']\n", - "\n", - "for chain in chains:\n", - " param_names = chain.getParamNames()\n", - " for name, label in zip(name_list, label_list):\n", - " param_names.parWithName(name).label = label" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "id": "d07b94e2", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[['# Expt' 'Colour' 'S8_Mean' 'S8_low' 'S8_high' 'sigma_8_Mean'\n", - " 'sigma_8_low' 'sigma_8_high' 'Omega_m_Mean' 'Omega_m_low'\n", - " 'Omega_m_high']\n", - " ['UNIONS $\\\\\\\\xi_\\\\\\\\pm(\\\\\\\\vartheta)$, Blind A' 'darkorange'\n", - " '0.7999861371466284' '0.06314803973690342' '0.05893888296160765'\n", - " '0.8621075476611365' '0.23146333595852553' '0.1775369759565658'\n", - " '0.2910399256634304' '0.13493574099977587' '0.07911322665839293']\n", - " ['UNIONS $\\\\\\\\xi_\\\\\\\\pm(\\\\\\\\vartheta)$, Blind B' 'crimson'\n", - " '0.828021240748265' '0.05962669788171815' '0.0689229332138428'\n", - " '0.9043558073678621' '0.23819570559254566' '0.20142194817753034'\n", - " '0.2855648058012865' '0.13776998824251813' '0.07550946033844397']\n", - " ['UNIONS $\\\\\\\\xi_\\\\\\\\pm(\\\\\\\\vartheta)$, Blind C' 'forestgreen'\n", - " '0.7656944786800725' '0.059302825285473704' '0.05571480015963448'\n", - " '0.8171988099453209' '0.22307663383848042' '0.16410095590993268'\n", - " '0.2969725477689531' '0.13842890774341807' '0.08267212562558135']\n", - " ['UNIONS $C_\\\\\\\\ell$, Blind A' 'royalblue' '0.8526580459586517'\n", - " '0.06130449685517725' '0.05980036342696382' '0.9409413763630565'\n", - " '0.22897867819558437' '0.2148772631199174' '0.27651742798133283'\n", - " '0.13143075949837665' '0.07271426428449712']\n", - " [\"$\\\\\\\\vartheta \\\\\\\\in [4',80']$\" 'darkorange' '0.8391383622379155'\n", - " '0.051868763411967334' '0.05902295252492895' '1.0293045987391145'\n", - " '0.15978910919454226' '0.26094446229683244' '0.22533650323796878'\n", - " '0.11077885903081033' '0.04228391897264244']\n", - " [\"$\\\\\\\\vartheta \\\\\\\\in [5',80']$\" 'darkorange' '0.8262197149477798'\n", - " '0.059741339121721415' '0.06326525363850344' '0.98051719928015'\n", - " '0.20096608004101424' '0.27151722638101905' '0.24587071743736716'\n", - " '0.13286800925272613' '0.057698857495527556']\n", - " [\"$\\\\\\\\vartheta \\\\\\\\in [7',80']$\" 'darkorange' '0.8174838817931142'\n", - " '0.06360812305922126' '0.06089305891666941' '0.9206253257714622'\n", - " '0.22958018282339543' '0.23156740229755857' '0.268430749841675'\n", - " '0.1330729887949352' '0.06920520433899596']\n", - " [\"$\\\\\\\\vartheta \\\\\\\\in [11',80']$\" 'darkorange' '0.7946580153616004'\n", - " '0.056697418999712146' '0.058560084849922034' '0.8656353752367024'\n", - " '0.21099726006198594' '0.1742952375973953' '0.2810682053375021'\n", - " '0.12317271689748549' '0.07282205006200493']\n", - " ['No baryons' 'darkorange' '0.7778633583399868' '0.06382266065372233'\n", - " '0.0600880939604872' '0.8255176217158618' '0.24904301122285633'\n", - " '0.16163906061217137' '0.3032199897045411' '0.14311028042067594'\n", - " '0.0910072307908466']\n", - " ['Halofit' 'darkorange' '0.7768797670850353' '0.0570505296366518'\n", - " '0.05779156691792786' '0.8570456491362484' '0.22966260121484694'\n", - " '0.1838455216750512' '0.2792256063898' '0.13395698046453647'\n", - " '0.08267197218325684']\n", - " ['No leakage correction' 'darkorange' '0.7778032458853116'\n", - " '0.06388565217480069' '0.0715520863135456' '0.7707536767164093'\n", - " '0.24120398709301716' '0.12974820149481003' '0.345394649845583'\n", - " '0.14304007855581574' '0.11009844659489898']]\n" - ] - } - ], - "source": [ - "param_values = np.array([\"# Expt\", \"Colour\", \"S8_Mean\", \"S8_low\", \"S8_high\", \"sigma_8_Mean\", \"sigma_8_low\", \"sigma_8_high\", \"Omega_m_Mean\", \"Omega_m_low\", \"Omega_m_high\"])\n", - "escaped = np.char.replace(legend_labels, '\\\\', '\\\\\\\\')\n", - "for i, chain in enumerate(chains):\n", - "\n", - " margestats = chain.getMargeStats()\n", - " likestats = chain.getLikeStats()\n", - "\n", - " s8_stats = margestats.parWithName('S_8')\n", - " sigma8_stats = margestats.parWithName('SIGMA_8')\n", - " omegam_stats = margestats.parWithName('OMEGA_M')\n", - "\n", - " param_values = np.vstack((\n", - " param_values,\n", - " [\n", - " escaped[i],\n", - " colours[i],\n", - " s8_stats.mean,\n", - " s8_stats.mean-s8_stats.limits[0].lower,\n", - " s8_stats.limits[0].upper-s8_stats.mean,\n", - " sigma8_stats.mean,\n", - " sigma8_stats.mean - sigma8_stats.limits[0].lower,\n", - " sigma8_stats.limits[0].upper - sigma8_stats.mean,\n", - " omegam_stats.mean,\n", - " omegam_stats.mean - omegam_stats.limits[0].lower,\n", - " omegam_stats.limits[0].upper - omegam_stats.mean,\n", - " ]\n", - " ))\n", - "print(param_values)\n", - "np.savetxt(f\"{root_dir}/param_values.txt\", param_values, fmt=['%s' for i in range(11)], delimiter=';')" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "id": "cc58ae5a", - "metadata": {}, - "outputs": [], - "source": [ - "# Load the value of the parameters\n", - "cosmo = np.loadtxt(f\"{root_dir}/param_values.txt\",\n", - " dtype={'names': ('Expt', 'colour', 's8_mean', 's8_low', 's8_high', 'sigma8_mean', 'sigma8_low', 'sigma8_high', 'omegam_mean', 'omegam_low', 'omegam_high'),\n", - " 'formats': ('U250', 'U20', 'U20', 'U20', 'U20', 'U20', 'U20', 'U20', 'U20', 'U20', 'U20')}, skiprows=1, delimiter=';')\n", - "expt = np.char.replace(cosmo['Expt'], '\\\\\\\\', '\\\\')\n", - "colours = cosmo['colour']\n", - "s8_mean = cosmo['s8_mean'].astype(np.float64)\n", - "s8_low = cosmo['s8_low'].astype(np.float64)\n", - "s8_high = cosmo['s8_high'].astype(np.float64)\n", - "sigma8_mean = cosmo['sigma8_mean'].astype(np.float64)\n", - "sigma8_low = cosmo['sigma8_low'].astype(np.float64)\n", - "sigma8_high = cosmo['sigma8_high'].astype(np.float64)\n", - "omegam_mean = cosmo['omegam_mean'].astype(np.float64)\n", - "omegam_low = cosmo['omegam_low'].astype(np.float64)\n", - "omegam_high = cosmo['omegam_high'].astype(np.float64)" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "id": "d3da35ed", - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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A2wiIiIiIiKiGmCATURERERERFQDDLCJiIiIiIiIaoABNhEREREREVENMMAmIiIiIiIiqgEG2EREREREREQ1wACbiIiIiIiIqAYYYBMRERERERHVAANsIiIiIiIiohpggE1ERERERERUAwywiYiIiIiIiGqAATYRERERERFRDTDAJiIiIiIiIqoBBthERERERERENcAAm4iIiIiIiKgGGGATERERERER1QADbCIiIiIiIqIaYIBNREREREREVAMMsImIiIiIiIhqgAE2ERERERERUQ0wwCYiIiIiIiKqAQbYRERERERERDXAAJuIiIiIiIioBhhgExEREREREdUAA2wiIiIiIiKiGmCATURERERERFQDDLCJiIiIiIiIaoABNpUlGwzP6/5ERERERESNTr/YDahG+vQwQg89idBDT0Hb5IT9uj+C+y8/A53LAQAY/+sfIvLkizC9+zy0/M3noXU5VPt3v/oz1fF8d92P0ENPKfsDQOTJF1XHd976MRjWrlSekw2GEfjRIzC9+zzkAlNBpfPW62ds62znNl28AQDgv/enAACdy4FsMAz7dVci8vRLaLrjlrKuUeSpl2C//sqy9i3Fd9f9aPn2F4o+Ftt/CLlgGMnXj6n2CT30FJy3Xq/8LCohX6vAvY9Cv3alci1z/hDSp4dhes95qtefPHIcY3+1E7lQpOC61oL8Pur4l+/CuuXSqttLRERERERLU0MH2Ia1K9Hy7S8gtv8QzO8+ryAIbLvnq9C67KrtLd/+ArRNTgR+9EhB4Cj/P3+b6eINJY+fPHIcvu8+gI5/uUsVSEaeegnDN3wZK/f+Y0FbKzn3+F//EM5br1eCbQAY/fO/Kfv6pE8Pw/+jRxDffwgA4L7jFtXNgXJIgfLHij6WPHIcAGC//krkAmFVMN90xy0zBuYzka9VsrcPpo3rC4LToQ/dhszpYbTd81UA0s+o5dtfwPhXfqjaz3fX/UifHsaKf/1uxW3I13bPV5F4/VjN2ktEREREREvTkhgirmtylnzMsHZV4f4uBzr+5bsI3Pso0qeHZ9+/xPGH//R/wX3HLQVZWvv1V8LQvRLjf/3DgudUcu7Iky+qgmsAaPvHO4u2ZbrY/kMYvvHLaP+HO2G7/krYrr+y4uA6fXoYySPHSz4veeS4KqObHlC/HsuW9yL00FMVnbMcrs9+rOC4Ondhptyy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h55CNhhG019+ZsZ5xcnXjqHtH+9Uvo8fOITAjx6B89brS2bh5XbG9x+S5oJPtiPnDyk3M1bv+xfl+ckjx+H77gPITF7jlm9/oext/nt/iuTrx5D1h6B1O2C//kq03fNV+O/9qao8l3Hjevh/9Ai0LkfBYmWVtpdovujanGj6wh9D11Y/oyXsV18M+9UXL3YzKqLraEHTV/8f6DpaFrspVIF6fP/Xm0bsj7XEvl0dXr/yNEo/42fm/NEIIcTsuy2eUCgEl8uFYDAIp5NvgHL47/0pJu56AMaN6+H67MdKZk5nWuRMfty0cUNVq1+P/vnfFKyQLgedXPCLlj0OrZubeR4iXi9q9fuvoX+Pso8sb0ukry/pvsw+urQskT43Hyrpf0tiiDipNd1xC9a+/UvYP/5B+O66HwPv/dScjxN9au41rEMPPQXnZz9WsD3Ze5zBNRERERERLTlLZog4qelcDjTdcQua7rhFCbDTp4cReXoqYI5Pm99tv+7KgsDXeev1JRdym0k2GEY2GIazSPZbLolFRERERES0lDDAXqLkMl8AlGHghrUrVUPCyylJZrp4A9IDwzOWBSsm+uRLRY+fnlbii4iIiIiIaKlggL1E6VyOirPOpczlOKXmfXNoOBERERERLVWcg01ERERERERUAwywiYiIiIiIiGqAATYRERERERFRDTDAJiIiIiIiIqoBBthERERERERENcAAm4iIiIiIiKgGGGATERERERER1QADbCIiIiIiIqIaYIBNREREREREVAMMsImIiIiIiIhqgAE2ERERERERUQ0wwCYiIiIiIiKqAQbYRERERERERDXAAJuIiIiIiIioBhhgExEREREREdUAA2wiIiIiIiKiGmCATURERERERFQDDLCJiIiIiIiIaoABNhEREREREVENMMAmIiIiIiIiqgEG2EREREREREQ1wACbiIiIiIiIqAYYYBMRERERERHVAANsIiIiIiIiohpggE1ERERERERUAwywiYiIiIiIiGqAATYRERERERFRDTDAJiIiIiIiIqoBBthERERERERENcAAm4iIiIiIiKgGGGBTWUKJ0LzuT0RERERE1Oj0i92AagwGBvHYkcfweO/jcJvd+PD6D+ML7/sCnGYnAOCbv/omfnn8l7hoxUW4c/OdcJqcqv1fuv0l1fF27N+Bx3sfV/YHgGePPas6/s0X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HnvsMX1dh8MhP/7xj0VE5MMPPxQA0tPTIyIie/bskfvvv19ft6amRl5++WUREfn4448FgLS3t4uIyHe/+13ZuHGjvm5jY6O88MILIiJy6tQpASCnTp0SEZEXXnhBGhsb9XU3btwo3/3ud0VEpL29XQDIxx9/LCIiL7/8stTU1Ojr3n///bJnzx4REenp6REA8uGHH4qIyI9//GNxOBz6uo899ph885vfFBGRkZERASDvvfeeiIgcOnRI0ov4E088IU8++aSIiEQiEQEgb731loiIvPPOOwJAAoGAiIjs3LlTHn/8cX1bk8kkb7zxhoiIvP/++wJABgcHRUTk6aeflocfflhft7y8XF577TURETl27JgAkKtXr4qIyHe+8x2599579XXr6+vlhz/8oYiIfPLJJwJAzp07JyIizz//vLS0tOjrNjc3y/e+9z0RETlz5owAkJMnT4qIyEsvvSTr1q3T1y2ae8Rwv0jnL+Sp39sqWx95QMTdKuJuFavVIq+/vFfE3SofvPXX6h5x5kMRd6s8843fk4fu26SvW+WskAN//p9F3K3y0XtvqHvEv/1vEXerPPfM12TTHbfo665bs1pe+tPdIu5WOfmLv1f3iF/9o4i7Vb733B9I800N+rotzRvk+T/+toi7Vc7980/VPeKD/ynibpUf7vuPUr96lb7uvZtuk+/8wS4Rd6tcPfkzdY94929F3K3y2l/+iZSXlerrPvzA3fL0V39HxN0qg+fU9fH+378m4m6VNw58X90jxtd9/N89JDt/Z6uIu1UCHao8vvPf94v0/ou89d/+n2V/j9DSoj1L5quon6MsI/MrI+5Weev1H6gy0vWJiLtVnnziS/LE1of1bW02m/ztgRel58wx+fu/fUWcTqf0t/1SxN0q3/z9fy+PfXGLvq6jxC4/3v+8iLtVPvzHv1FlxPVzEXer7Pn2k3L/3Rv1dWuqnfKjP/tPMnbphPzv//dvpKWlRX71//1ELn76c/nT//QHsrGlSV+3sWGNvPAnfyjibpVTv3xblZFfvi3ibpUX/uQPpbGhXqTzFyKxYFE/R7WysCzLciwoO7Y+KDu2q2sr3vt/VFn+65dE3K3y7sH/os798j+LuFvlqf/wOMtyjssyADn02osi7lZ5738cUM+7C/80z7J8u17m+Jk4syxnU44NIoXdAcbn86GyshKffPIJvvjF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UXEoXQN88SX1Wog2fFn9FKKSGmDTbvVKy0+hl41CVMjlNVss3ytLySr+v7O1XMo77/VTZDVN1ze+8Q1Eo9FFGVH85z//OQ4dWmHNlj/ep/pGA1MHNyOi4lC2Bvitv1SvlB1HDXD3s+qVlh+WjZWN5XtlKeH/e8XivX6KrOfB/sEPfoCvfOUrOU3E/v370dLSsiQjlRcUrUl428EbD7JGREREREREBS3rAPvFF19ERUUF9u/fn5MEtLW14bXXXkN7e3tO9ldUtPm62TSciIiIiIio6GUdYANAe3s7jh49mpME7N69G7/+9a9zsi8iIiIiIiKifMl6HmxN+gjgC5Gr/RARERERERHl07xqsImIiIiIiIgoEwNsIiIiIiIiohxggE1ERERERESUAwywiYiIiIiIiHKAATYRERERERFRDjDAJiIiIiIiIsoBBthEREREREREOcAAm4iIiIiIiCgHGGATERERERER5QADbCIiIiIiIqIcYIBNRERERERElAMMsImIiIiIiIhygAE2ERERERERUQ4wwCYiIiIiIiLKAQbYRERERERERDnAAJuIiIiIiIgoBxhgExEREREREeUAA2wiIiIiIiKiHGCATURERERERJQDDLCJiIiIiIiIcoABNhEREREREVEOMMAmIiIiIiIiygEG2EREREREREQ5wACbiIiIiIiIKAcYYBMRERERERHlAANsIiIiIiIiohxggE1ERERERESUAwywiYiIiIiIiHKAATYRERERERFRDjDAJiIiIiIiIsoBc74TsCCeTqDtTaDtIGCvBlp2Ag98H7A7gRP7gK7jwKAL2LwH2PwsULdl9v0NuIBf7gaiHuCPOrJLS8QDnHwFcDartERG1XGJiIiIiIhoRSjuGmxnE/Doq0BlE9C4Tf1ud6r3Hn0VuO1rgM0JbH/zxsE1oNZ59NX5peXt+1QQv3mPCvRP7FNfAKRrOzi/fRMREREREVHBK+4AW2OvnmG5M3f7ms2ASwXyzqaJZTsOZ/4NAAOnst83ERERERERFYXlEWDnW2R0amDeuC3z77aDgLt16dJERERERERES2rlBdgRD3DyAHDpCHDsWVX7PBfaNpeOqN81XcdVP3Bvp1p+8oDa7+tV6j1tna5jmesQ0fIU6Ac++Uv1StMLDQNn3lSvRDMJ9AP/50dAeDTfKaF8CQ8D598Ggryf5h2f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d//AMNrOT1wfFy5dRXevKjfRaAyutnb4/Or6HhgawelzE9fHxSvXcK27bzy/E3C1tcPjVf+boeExuNomyuPlzm50dvVO5HdbO0bH1P9m1OOH67PPVsQ9IleK+jnKMqLyO5syMuaFq619oox09eLK1R59W1dbO4ZHPCq/PT642tonykjXdVzq6NLXPX3uIgaH1PPC51f5HYupZ0B3rxvtlyfyu+38ZbgHVR4GgqGM/O7tG8jI73MXrqDPrZ4toZDKw1BI5Xefewjn2ifWLfbnaC4VXFnu6kPHNfV8FhG42toxMuoBMHFt6WW56zrLMgq4LF+ZWJefiRdQlqXAeb1eASBr1qzRl23atEmee+45ERG5fPmyAJCPPvpIREQOHDggVVVV+roPPfSQPPPMMyIi0tfXJwDkgw8+EBGR119/XaxWq77u1q1b5amnnso47rvvvisiIj/5yU8EgMTjcRER2bFjh+zYsUNEROLxuACQn/zkJyIi8u677woA8Xq9IiLy1FNPydatW/XjWK1Wef3110VE5IMPPhAA0tfXJyIizzzzjDz00EP6ulVVVXLgwAEREfnoo48EgFy+fFlERJ577jnZtGmTvu66devkpZdeEhGRkydPCgA5c+aMiIh873vfk+bmZn3dlpYWef7550VE5Ny5cwJAPvnkExER+eEPfyj19fX6uvfee6985zvfERGRq1evCgA5duyYiIi89tprUl5erq/78MMPy9NPPy0iIoODgwJA3n//fREReeONN8RkMunrPv7447Jz504REQkEAgJA3nnnHREReeuttwSARCIRERF58skn5YknntC3BSCHDh0SEZH33ntPAMjIyIiIiHzzm9+Uxx57TF/X4XDIj3/8YxER+fDDDwWA9PT0iIjInj175P7779fXrampkZdffllERD7++GMBIO3t7SIi8t3vflc2btyor9vY2CgvvPCCiIicOnVKAMipU6dEROSFF16QxsZGfd2NGzfKd7/7XRERaW9vFwDy8ccfi4jIyy+/LDU1Nfq6999/v+zZs0dERHp6egSAfPjhhyIi8uMf/1gcDoe+7mOPPSbf/OY3RURkZGREAMh7770nIiKHDh2S9CL+xBNPyJNPPikiIpFIRADIW2+9JSIi77zzjgCQQCAgIiI7d+6Uxx9/XN/WZDLJG2+8ISIi77//vgCQwcFBERF5+umn5eGHH9bXLS8vl9dee01ERI4dOyYA5OrVqyIi8p3vfEfuvfdefd36+nr54Q9/KCIin3zyiQCQc+fOiYjI888/Ly0tLfq6zc3N8r3vfU9ERM6cOSMA5OTJkyIi8tJLL8m6dev0dYvmHjHcL9L5C3nq97bK1kceEHG3irhbxWq1yOsv7xVxt8oHb/21ukec+VDE3SrPfOP35KH7NunrVjkr5MCf/2cRd6t89N4b6h7xb/9bxN0qzz3zNdl0xy36uuvWrJaX/nS3iLtVTv7i79U94lf/KOJule899wfSfFODvm5L8wZ5/o+/LeJulXP//FN1j/jgf4q4W+WH+/6j1K9epa9776bb5Dt/sEvE3SpXT/5M3SPe/VsRd6u89pd/IuVlpfq6Dz9wtzz91d8RcbfK4Dl1fbz/96+JuFvljQPfV/eI8XUf/3cPyc7f2SribpVAhyqP7/z3/SK9/yJv/bf/Z9nfI7S0aM+S+Srq5yjLyPzKiLtV3nr9B6qMdH0i4m6VJ5/4kjyx9WF9WwBy6LUXRdyt8t7/OKDKyIV/EnG3yjd//9/LY1/coq/rKLHLj/c/L+JulQ//8W9UGXH9XMTdKnu+/aTcf/dGfd2aaqe8/Gf/ScTdKh+//3eqjPzLERF3q3z32W/IxpYmfd3GhjXywp/8oYi7VU798m1VRn75toi7VV74kz+UxoZ6kc5fiMSCRf0c1crCsizLsaDs2Pqg7Niurq147/9RZfmvXxJxt8q7B/+LOvfL/yzibpWn/sPjLMsFXZZv18scPxNnluVsyrFBZPzrpwLl8/lQWVmJTz75BF/84hcBqG8+ysvLsX79ekQiEZw/fx633norysvLMTAwALfbjbvvvhuA+rbObrejsbER8XgcZ8+eRXNzMyorKzE0NITe3l7ce++9ANS3dWazGTfffDOSySTOnDmDm2++GVVVVRgZGUFXVxfuvfdeGAwG/Vv35uZmiAg+++wzNDY2YtWqVRgbG8PVq1dx9913w2Qy4erVq0gkErj11lsBqBrshoYG1NbWwuv1oqOjA5s2bYLFYkFXVxcikQhuu+02AKoGu76+HnV1dfD7/bh8+TI2btwIu92Onp4e+P1+bNy4EYCqwa6pqcGaNWsQDAZx8eJF3HHHHSgpKcH169fh8Xhw5513AlDfflZWVqKhoQHhcBgXLlxAS0sLysrK0N/fj6GhIWzevBmAqsEuLS3Fhg0bEI1G8fnnn+OWW25BRUUFBgYG0N/fj3vuuUfPb5vNhptuuknP76amJjidTgwNDaGnpwdbtmzR89tkMqGpqUnP75tuugnV1dUYHR3FtWvXcM8998BoNKKzsxOpVAq33HILAFU7tWHDBtTU1Oj5vXnzZpjNZly9ehXxeBwtLS0AVO3U2rVrsXr1avh8Ply5cgV33XUXrFYruru7EQqFcPvttwNQ39atXr0a9fX1CAQCuHTpkp7fvb298Pl8en6fO3cO1dXVWLt2LUKhENrb23H77bfD4XCgr68Po6OjuOuuu/RrtqKiAg0NDfo1q+W32+3G4OCgnt/t7e1wOBzYsGEDYrEYzp07p+f34OAg+vr69Py+dOkSLBYLbr75ZiQSCbS1tenX7PDwMLq7u/X8vnLlCoxGI5qampBKpXD69Okp+a1ds52dnUgmk/o163K5sH79etTW1sLj8aCzs1O/Zq9du4ZoNKpfs6dPn8aaNWtQV1en5/edd94Jm82G7u5uBINB3HHHHXp+19bWYs2aNXp+a9dsb28vvF5vxjXrdDqxbt06/Zq97bbbUFpaiv7+fgwPD2PTpk3FdY/YeCtM/f+Kq24/EjDj1qYN6h5xth0Na+pQW1MFry+Ajmu92HTHLbBYzOjq6UckGsVtt9yk7hGfX0L96lWoq10FfyCIy5092NhyM+x2G3quu+EPhLDxtiZ1j7hwBTXVTqypq0EwGMbFji7ccetNKCmx43r/IDxeP+68vVnld3sHKivK0LC2DuFwBBcuX0NL8waUlTrQPzCMoZExbN6oro8Ll66i1FGCDQ31iEZj+PxiJ265uQEV5WUYGBpB/8Aw7rlLXR8Xr1yDzWrFTRvWIh5P4OyFK2hqXAdnZTmGhsfQ0zeALZtVebzc2Q2TyYimxgaV359fxk3r16C63IbRwT5ci6/FPfd/cdneI+rr67Fu3Tp4vV5UVFRgvor6OcoyMr8yUlWJ0TEvrvX04567WlQZ6epFKiW45eb1qoy0tWPDunrUrHJizOPD1e4+bN54iyojXdcRTyTQ0tyoysi5i1hbV4vVtdXw+QO4crUXd93eDKvVgu5eN0LhCG6/VeV32/nLWF1ThfrVNQgEQ7jU0a3nd2/fAHz+oJ7f5y5cQXVVJdbW1yIUiqD9yjXcfstNcDjs6HMPYXR4CHc11QINj+L85WtF+xzVyuCyLMuJMDr+9X8BljI03zJels9eRGNDPVZVT1xbd995q/pM3HUdiWSSZblQy3LAi9s3VAMNj6LtwhV+Jk4ry3V1dXMux0UTYC/0pkREVHDiIaD3BGAtB8z2fKemeCQiQMwPNDwKWBz5Ts2iyfWH8qJ8jrKMrGzLpKwv67LMMrq8LJMytxiyKX9F0webiIiIiIiIqJAxwCYiIiIiIiLKAQbYRERERERERDnAAJuIiIiIiIgoBxhgExEREREREeUAA2wiIiIiIiKiHGCATURERERERJQDDLCJiIiIiIiIcoABNhEREREREVEOMMAmIiIiIiIiygEG2EREREREREQ5UBABdltbW76TQERERERERLQg8w6w29rasHbt2pwk4oUXXsDu3btzsi8iIiIiIiKifJh3gP3YY4/hww8/1P/evXs3DAYD3nnnnaz3dfToURw5ciT7bT2dwIl9wOtVwN81T31fe+/wdmDAlXW6AKjt3rpv+v3PR9dxtb/D23OzPyIiIiIiIioI8wqwH3zwQbS0tGDz5s36ssbGRhgMBtx1113zSsivf/1rPP3009lt5GwCHn0VeOD7QGRUBdTpHn0V2LwH2HUMqNsyr3ShbovaT640bgMeHE8vZa/t4PTLT+wDju5a2rQQERERERGlmVeA/Zvf/AaffvppxrIXX3wRqVQqI+jOxubNm1FWVja/puJ2J7DjMPCbA6pWO50zBzXP9uqF7yOdzZnb/a0kA6emX964Hbjta0ubFiIiIiIiojRZB9i7d+9GZWXlYqQFO3fuxNtvvz2/jRu3ARu2sRZzOWs7CLhbp3+vcRvQsnNp00NERERERJQm6wD7yJEj+O3f/u2MZfv374fRaITBYNBroB988EF9mcVi0UcK1/pqGwwG7NixI2M/hw4dQiQSme+5qFrsQdfMzYg1Jw8Al46on5MH5n88bT/aqybimVh27Nkb9/9+6z7VV1xr4n6j7SMetbztoHo9eUD17U7/cmGmtM2m7WDmz3TnOjnPLh1R/dOP7lJpOLFP/cy0fC7pmy4dXceBrmOAt1Ntk56G2frJz5RurS/8W/ep7bX3J3czILqRQD/wyV+qV8qt0DBw5k31SvnB63t5YZmiYsTrluaigJ5XWQfYHo8HX//61zOWac3D03366ac4ffo0AOCll17Sm44fOnQIa9aswT/8wz/g6NGj0x5jPgOlAVBNxR95VQVJEc/06xzdpfpVt+yc+JnPgGNHd6k+4C07gQf2qoKvBcInX5nY9/Y31bozpQdQta/fOjXR1/tG2x/brZpEb94DfGEf0Pam2seOwzdO20xOHgA8HWqfm/cAlU0Tge9sedayU6Xb06ma0mvNtGdafsO8myEdjduAzc+qvx/Yq340M/WTny3djdvUNlGP6g+vpeXSkfkPiEcrU7Af+Le/Uq+FqPtXwAdfB975LfXa/at8p2juwsPA2UPqlfKj0K/vQlIMZY1liooRr9vsFcP9KNcK6Hk1rz7Y3/jGN+a03ubNm2E2m/Haa69lLK+oqJhxH2azGR999NF8kqU8sFcFdMem6cs94FI1l43bJpY5m1SA1XV87sfwdKpALL1JcuN2FegCqpa1O21/lU2Zf6c7eUAN0uZsmlh2o+0vHQFWb5lIv7dzou/5jdI2nYgH+HifSoem7U21r7nkmc2p0lC3JTPYnW75bOmbLR03Mrmf/FzSba9W6Utfp3I8P4mWg+5fASf2Ap4rQCqmXk/sXRkPWqKlxLJGRIWC96O8My/2Ab7yla/ggw8+0P/ev38/HnnkkZkTZDbD7XYv7KA7DgNv3ze1JnKgVQVQkzmbVPPj9EBrNt3HVfCYHpRHRiYCQa0mOeJRwVpkdPpRw7Wm1Om1sXPZfvUWtTw9KNd+v1HapjPQqraxO6emoe3g3PJsunWmWz5b+mZLR7bm+r+evI7dyRHeaX7e+wpgsma3jQiQjAIGI2Aw5D5N4RHtQJmvH/8ZUJLjwRsXQyqe7xSQZj7Xdy4sdhnJlWIpayxTVMw+eg4wWvKdisK3kPuRCCApwGQr7HvudJKxfKdAl1WArfWjzsbRo0f1/tZHjx7F22+/jfb29lm3GRwczPo4Geq2qObFR3cBD6T1qZ2tmXY2Ih4VmKUH5Om/D7hUM+/G7WrgNec0gV7Uo2pqveNzeac3cb7R9nc/q2p26+5XAfD2tNrpG6VtOlHP7OeaS7Olb659xTWezunzVjsO0VIKD+U7BXMnCSC0wPssrSzFdH0XEpY1otyJjOU7BcWN96Mlk1WAPd8puJxOJz788MM5rZtIJOZ9nAyPvApcvBk4OT4XNqACuZOvTF3X05ndFE91W6bfjxbUHd6q+lRrwZ+2PD0grGxStaXbDwF/d7PqX+xsUuvOZfvth1RtcMvOzCBztrSl1wynW71l+iA74sldns0lfbOlY7q0D7pmDrBznW6iGympLcwabElOXW4wF1at2kxScX6gKhTzub5zoZhqsIuhrLFMUTGzV7EGey4Wcj8q9hrsAvkyeF5NxNva2rIKgv/0T/8Uf/7nf44HH3wQf/EXfzHruslkEo2NjdklyNMxdZndCTx+CPhlWl/sui2q1je9b67WjDybKZ4at6n9TO5L3H1cBc5RT2bgpzU5ni4gtDvVFwDHngV2jY+SfaPtB06pbaZL82xpm+kctQHHTh7IbK6ubZOLPJtr+mZLR3r/aE/nRD/06cz3f82ab5qv3/9QXXfZiIeA3hOAtRww23OfJq0fFgxQTcTGXx95BdjwpdwfL9dG2oFffCvfqSBgftd3Lix2GcmVYilrLFNUzL70N8Cq2/OdisK3kPtRIgLE/EDDo4DFsfhpzaUBl+oiXACyHuTMYDDgZz/72YzvT9d/+sUXXwQAuFyuGw6QJiL43d/93bklxtOpmoH/5oAKUCcHRy07pzaP3nVM9cHVpoC6+FPg26dmPsaASzXh1ppyp+/H/Ru1D20aqJad6gPIF/ZO9K++dET1I+46prbrOq5q1QdaJ/YX9agg8vB21Qd5tu0B1XT8NYOa2uvvmtVUU+nTas2UttnsOKz6QqdPa6VtM1ueaeej5Y/W13um5TdK32zpcDapLxZO7FP5pX0JMdv/aKZ0T7fNyQPq/3LmzeybqxMVog1fBh49AFTdAhit6vXR/1pYH/iJlgOWNSIqFLwf5Z1BROTGq024/fbbUVlZiU8//VRftn//fvzoRz9CJBKBwWDAF77whYz3te1uvfXWGafmAlTN+D333JMx5ZfP50NlZSW8Xi8qKiqySery5OlUI21vPzQ+IJdnIki8bddEc3giWhqBfjUmwuZngbI12W1bLLVz+RIaBi6/B9z6+4CjZmJ5MX/DnoVcPf8WtJ+FXN+5wDKSWzOVqUK1TMp6QZTlxbIUZbTYrttiVsxlbpGfV9mUv6wD7HfeeQfPPPMMwuHwghI5nR07dmBwcDAjOC/Im0k+ndinarAn18wPuNRFlT7gGREVNgYP81PMHwCysKw/lM8Vy8jKtkzK+rIuyyyjy8syKXOLIZvyl3UT8W984xuIRqPzGlH8Rn7+85/j0KFDOd/vstK4Hbg0zdRVXcfVe0RERERERJQX8xrk7Ac/+AG+8pWvoK+vL2cJ2b9/P1paWnIzgvhyptVcnzww0QdZG118PoOOERERERERUU7MK8B+8cUX8fbbb2P//v36AGYL0dbWhtdeew1jY5w6Yk4at914bmsiIiIiIiJaUlk3Ede0t7fPOmBZNnbv3o1f//rXOdkXERERERERUT7MqwZbM3mk8Hzvh4iIiIiIiChf5l2DTUREREREREQTGGATERERERER5QADbCIiIiIiIqIcYIBNRERERERElAMMsImIiIiIiIhygAE2ERERERERUQ4wwCYiIiIiIiLKAQbYRERERERERDnAAJuIiIiIiIgoBxhgExEREREREeUAA2wiIiIiIiKiHGCATURERERERJQDDLCJiIiIiIiIcsCc7wTciIgAAHw+X55TQkSUY/EQ4A8CpjhgsuU7NcUjGQWSMcDnAyyJfKdm0WjPPe05OF9F/RxlGVnZlklZX9ZlmWV0eVkmZW4xZFOOCz7A9vv9AID169fnOSVERERLz+/3o7Kyct7bj4yMAOBzlCjfWJaJit9cynHBB9hr165FT08PysvLYTAY8p2cDD6fD+vXr0dPTw8qKirynZwlx/Pn+fP8V+75A8yDxT5/EYHf78fatWsXtJ/q6moAQHd394I+3BejlXqNrtTzBgrz3FmWZ1eI/7NcWK7nBSzfc5vtvLIpxwUfYBuNRjQ0NOQ7GbOqqKhYVhdXtnj+PH+e/8o9f4B5sJjnn4sP0UajUd/XSv0/rdRrdKWeN1B4586yfGOF9j/LleV6XsDyPbeZzmuu5ZiDnBERERERERHlAANsIiIiIiIiohxggL0ANpsNL730Emy2lTlqIs+f58/zX7nnDzAPiuX8iyWdi2GlnvtKPW9geZ/7cj03nlfxWa7nlqvzMshC5wwgIiIiIiIiItZgExEREREREeUCA2wiIiIiIiKiHGCATURERERERJQDDLCJiIiIiIiIcoABNhEREREREVEOMMAmIiIiIiIiygEG2EREREREREQ5wACbiIiIiIiIKAfM+U4AERWWzs5OvPnmmxnLvv/97+Pdd9/Ftm3b0NTUlKeUERERERUej8eDV155BatWrYLT6QQAdHR0oLm5GXv27Mlv4mjJGURE8p0IIioMx48fx+HDh6cE2Lt27YLL5UJHR0eeUkZERERUeA4ePIh9+/bhn/7pn7Bly5aM9/bt24cjR47g1KlTeuBNyx8DbCICoL593bp1K06dOjXlvSNHjuDYsWNTAm8iIiKiler48ePYvn07Dh8+jJ07d067zn333QcA036+ouWJfbCJCADw7rvv4v7775/2vaamJmzfvn2JU0RERERUuF599VUAmDG4BoCvfe1rcLlcOH78+FIli/KMATYRAVB9hWa6+Tc1Nc368CAiotw4fvw47rvvPhgMhik/Bw4cyHfyiChNa2vrDcem0ZqNHzt2bCmSRAWAATYRAQCeffZZdHZ2wmAw4Nlnn80IttlviIho8R05cgT79u3DoUOHMDY2hr1796KpqQkiAhHB3r17851EIkpTXV2Nzs7OWdfR3m9ubl6KJFEBYIBNRABULfXY2Bj27Nmj9ylijQkR0dLo7OzE7t27cfjwYWzZsgVOpxOvvvoqOjs7b/gBnojyQ2vdN1sZ1QaI/epXv7okaaL84yBnRDStzs5OvPrqqzh48CA6Ojr0JlCdnZ167XZHRwe+9rWvTRk1k4iIsrN9+3Zs3759Si21wWDAqVOnMu6zvA8TFY6qqip8//vfn7GFSXNzM7Zt28aBYlcQBthEhM7Ozhn7EDU3N+PVV1/Vv6Xdt2+fPqgHoKbwOnz48JKkk4houTIYDBlfZgJqdoeqqipM/qjG+zBR4Thy5AheeeWVaUcJd7lc2Lp1K8bGxvKQMsoXNhEnWuHSa0Jmkl4zcuTIETZXJCLKIZfLBQBTvuh89913p62Z5n2YqHDs3Llzxr7Yb775Jg4dOpSHVFE+mfOdACLKr+PHj+v9gyZzuVxoamrK+ND37LPPorm5GXv37sWqVasyalGIiCh7Tqdz2sEk33zzzWnvsbwPExWGI0eOYOfOnXjzzTenLa+jo6N6C8CDBw9iz5498Hg8evc7bYDZ0dFReDwebNu2TR93gTO4FC8G2EQr3LFjx+DxeKY0E+/s7MS+ffumNDvcu3cvOjo6cOTIEQDAtm3bljS9RETLjfZFpsfj0QPtffv2Ydu2bdPeY3kfJioMx44dw5YtW1BdXT3lPY/Hgy984QtTBio8fvw49u7di+bmZtx3333Ys2cPgInxFnbu3AmXy4V9+/YxwC5SDLCJVrjq6mocPnwYBw4cQEdHh/7hbtWqVVPmbPR4PPootwBw4MAB3HfffRgbG+NUXkREC3D48GG88soraG5u1j+YT/fhmvdhosIxOjqqT7/V1NSUUYPd2tqKffv2Yd++fQCg99HeuXMnPB4PAOjBtcvlwrZt2/QuIa2trRy4sIhxkDMimrMjR45gdHRUfyAAqqnirl27WINCRLQEeB8mKn5HjhzBsWPH9JHFtSlRtZHIt2/frrdioeLDQc6IaM6ampqm9Nd2Op24//7785QiIqKVhfdhouJ37NgxbN++PePv9GC6tbUV27Ztw8GDB/ORPFog1mATUVa00WudTqc+IAebMRERLR3eh4mK2/bt23H48GG9W8d9992XMc3Xrl27sH37dnz1q19l148ixACbiIiIiIiIKAfYRJyIiIiIiIgoBxhgExEREREREeUAA2wiIiIiIiKiHGCATURERERERJQDDLCJiIiIiIiIcoABNhEREREREVEOMMAmIiIiIiIiygEG2EREREREREQ5wACbiIiIiIiIKAcYYBMRERERERHlwP8PmHwzD5QcV8oAAAAASUVORK5CYII=", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "from matplotlib.gridspec import GridSpec\n", - "\n", - "fig = plt.figure(figsize=(10, 6))\n", - "gs = GridSpec(1, 3, width_ratios=[1, 0.5, 0.5])\n", - "ax1 = fig.add_subplot(gs[0])\n", - "ax2 = fig.add_subplot(gs[1], sharey=ax1)\n", - "ax3 = fig.add_subplot(gs[2], sharey=ax1)\n", - "\n", - "axs = [ax1, ax2, ax3]\n", - "\n", - "params = [\n", - " (s8_mean, s8_low, s8_high, r\"$S_8$\"),\n", - " (sigma8_mean, sigma8_low, sigma8_high, r\"$\\sigma_8$\"),\n", - " (omegam_mean, omegam_low, omegam_high, r\"$\\Omega_m$\"),\n", - "]\n", - "reference = r\"UNIONS $\\xi_\\pm(\\vartheta)$, Blind A\"\n", - "\n", - "separation_after = [\n", - " r\"UNIONS $C_\\ell$, Blind A\",\n", - " r\"$\\vartheta \\in [11',80']$\",\n", - " r\"Halofit\"\n", - "]\n", - "list_section_index = [\n", - " r\"(ii)\",\n", - " r\"(iii)\",\n", - " r\"(iv)\",\n", - " r\"(v)\",\n", - " r\"(vi)\",\n", - " r\"(vii)\"\n", - "]\n", - "\n", - "preliminary_watermark = True\n", - "blind_axes = True\n", - "row_spacing = 0.1\n", - "\n", - "index_ref = np.where(expt == reference)[0][0]\n", - "\n", - "y = np.arange(len(expt))\n", - "for ax, param in zip(axs, params):\n", - " means, lows, highs, label = param\n", - " for i, mean, low, high, color in zip(y, means, lows, highs, colours):\n", - " ax.errorbar(mean, 0.05+i*row_spacing, xerr=np.array([low, high])[:, None], fmt='o', color=color, ecolor=color, elinewidth=2, capsize=3)\n", - " ax.set_xlabel(label, fontsize=14)\n", - " \n", - " ax.grid(False)\n", - " ax.tick_params(axis='y', left=False, labelleft=False)\n", - " if label == r\"$S_8$\":\n", - " ax.axvspan(s8_mean[index_ref] - s8_low[index_ref], s8_mean[index_ref] + s8_high[index_ref], color=colours[index_ref], alpha=0.2)\n", - " ax.set_xlim(0.25, 0.95)\n", - " if blind_axes:\n", - " ref_tick = np.mean(s8_mean[:4])\n", - " ax.set_xticks(\n", - " [ref_tick + i*0.1 for i in range(-5, 2)], labels=[]\n", - " )\n", - " elif label == r\"$\\sigma_8$\":\n", - " ax.axvspan(sigma8_mean[index_ref] - sigma8_low[index_ref], sigma8_mean[index_ref] + sigma8_high[index_ref], color=colours[index_ref], alpha=0.2)\n", - " ax.set_xlim(0.5, 1.2)\n", - " if blind_axes:\n", - " ref_tick = np.mean(sigma8_mean[:4])\n", - " ax.set_xticks(\n", - " [ref_tick + i*0.2 for i in range(-2, 2)], labels=[]\n", - " )\n", - " elif label == r\"$\\Omega_m$\":\n", - " ax.axvspan(omegam_mean[index_ref] - omegam_low[index_ref], omegam_mean[index_ref] + omegam_high[index_ref], color=colours[index_ref], alpha=0.2)\n", - " ax.set_xlim(0.1, 0.5)\n", - " if blind_axes:\n", - " ref_tick = np.mean(omegam_mean[:4])\n", - " ax.set_xticks(\n", - " [ref_tick + i*0.1 for i in range(-2, 3)], labels=[]\n", - " )\n", - "\n", - "\n", - "axs[0].set_yticks(0.05+y*row_spacing)\n", - "axs[0].set_yticklabels([])\n", - "for label, color in zip(expt, colours):\n", - " axs[0].text(0.26, 0.05 + row_spacing * np.where(expt == label)[0][0], label, fontsize=12, ha='left', va='center', color=color)\n", - "# Add separation lines\n", - "for i, sep in enumerate(separation_after):\n", - " index_sep = np.where(expt == sep)[0][0]\n", - " for ax in axs:\n", - " ax.axhline(row_spacing * (index_sep + 1), color='black', linestyle='dotted', linewidth=1)\n", - " axs[0].text(0.25, 0.05 + row_spacing * (index_sep + 1), \n", - " list_section_index[i], fontsize=14, fontweight='bold', va='center', ha='right')\n", - "\n", - "\n", - "# --- Add section labels (i), (ii)) ---\n", - "axs[0].text(0.25, 0.05, \n", - " r\"(i)\", fontsize=14, fontweight='bold', va='center', ha='right')\n", - "\n", - "if preliminary_watermark:\n", - " plt.figtext(0.5, 0.5, 'PRELIMINARY',\n", - " fontsize=50, color='gray',\n", - " ha='center', va='center',\n", - " alpha=0.3, rotation=330)\n", - "\n", - "plt.gca().invert_yaxis()\n", - "\n", - "plt.tight_layout()\n", - "\n", - "plt.savefig(\"./plots/whisker_plot_config_space.png\", dpi=300)\n", - "plt.show()" - ] - }, - { - "cell_type": "code", - "execution_count": 213, - "id": "a172104f", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "['royalblue',\n", - " 'crimson',\n", - " 'forestgreen',\n", - " 'royalblue',\n", - " 'royalblue',\n", - " 'royalblue',\n", - " 'royalblue']" - ] - }, - "execution_count": 213, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "list(colours)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "6fe01467", - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "sp_validation_3.11", - "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.11.0" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/cosmo_inference/notebooks/2D_cosmic_shear_paper_plots/2025_12_10_plot_covariance.py b/cosmo_inference/notebooks/2D_cosmic_shear_paper_plots/2025_12_10_plot_covariance.py deleted file mode 100644 index 08037537..00000000 --- a/cosmo_inference/notebooks/2D_cosmic_shear_paper_plots/2025_12_10_plot_covariance.py +++ /dev/null @@ -1,63 +0,0 @@ -# %% -import IPython - -ipython = IPython.get_ipython() - -import os -import numpy as np -from astropy.io import fits -import matplotlib.pyplot as plt -import matplotlib.ticker as mticker -import seaborn as sns -from getdist import plots, MCSamples - -plt.style.use( - "./matplotlib_config/paper.mplstyle" -) - -plt.rcParams["text.usetex"] = True - -sns.set_palette("husl") - -#Matplotlib inline if in jupyter -if ipython is not None: - ipython.run_line_magic("matplotlib", "inline") - -# %% -cosmosis_dv = fits.open( - "/home/guerrini/sp_validation/cosmo_inference/data/SP_v1.4.6_leak_corr_A_10_80/cosmosis_SP_v1.4.6_leak_corr_A_10_80.fits" -) - -cov_matrix = cosmosis_dv["COVMAT"].data -# %% -def cov_to_corr(cov): - """Convert covariance matrix to correlation matrix.""" - diag = np.sqrt(np.diag(cov)) - corr = cov / np.outer(diag, diag) - return corr - -# %% -labels_cov = [ - r"$\xi_+(\theta)$", - r"$\xi_-(\theta)$", - r"$\tau_0(\theta)$", - r"$\tau_2(\theta)$", -] -# %% -plt.figure() - -plt.imshow(cov_to_corr(cov_matrix), vmin=-1, vmax=1, cmap="coolwarm") -plt.colorbar(label="Correlation coefficient") - -plt.xticks( - ticks=[10, 30, 50, 70], - labels=labels_cov, -) -plt.yticks( - ticks=[10, 30, 50, 70], - labels=labels_cov, -) - -plt.savefig("./plots/cov_matrix_SP_v1.4.6_leak_corr.pdf") -plt.show() -# %% diff --git a/cosmo_inference/notebooks/2D_cosmic_shear_paper_plots/2025_12_10_plot_leakage_prior.ipynb b/cosmo_inference/notebooks/2D_cosmic_shear_paper_plots/2025_12_10_plot_leakage_prior.ipynb deleted file mode 100644 index 67e72292..00000000 --- a/cosmo_inference/notebooks/2D_cosmic_shear_paper_plots/2025_12_10_plot_leakage_prior.ipynb +++ /dev/null @@ -1,464 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 5, - "id": "ee91f375", - "metadata": {}, - "outputs": [], - "source": [ - "import os\n", - "\n", - "# Trick to plot with tex on candide\n", - "os.environ[\"LD_LIBRARY_PATH\"] = \"\"\n", - "os.environ[\"CONDA_PREFIX\"] = \"/home/guerrini/.conda/envs/sp_validation_3.11\"\n", - "\n", - "import numpy as np\n", - "from astropy.io import fits\n", - "import matplotlib.pyplot as plt\n", - "import matplotlib.ticker as mticker\n", - "\n", - "import seaborn as sns\n", - "from getdist import plots, MCSamples\n", - "\n", - "from shear_psf_leakage.rho_tau_stat import RhoStat, TauStat, PSFErrorFit\n", - "\n", - "plt.style.use(\n", - " \"./matplotlib_config/paper.mplstyle\"\n", - ")\n", - "\n", - "plt.rcParams[\"text.usetex\"] = True\n", - "\n", - "sns.set_palette(\"husl\")\n", - "\n", - "%matplotlib inline\n", - "\n", - "g = plots.get_subplot_plotter()\n", - "\n", - "g.settings.legend_fontsize = 10\n", - "g.settings.axes_fontsize=10\n", - "\n", - "def cov_to_corr(cov):\n", - " \"\"\"Convert a covariance matrix to a correlation matrix.\"\"\"\n", - " d = np.sqrt(np.diag(cov))\n", - " corr = cov / np.outer(d, d)\n", - " corr[cov == 0] = 0\n", - " return corr" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "id": "90e5396a", - "metadata": {}, - "outputs": [], - "source": [ - "data_path = \"/home/guerrini/sp_validation/cosmo_inference/data/\"\n", - "\n", - "path_cosmo_val = \"/home/guerrini/sp_validation/notebooks/cosmo_val/output/\"\n", - "\n", - "versions = [\"SP_v1.4.6\", \"SP_v1.4.6_leak_corr\"]\n", - "roots = [\n", - " \"SP_v1.4.6_no_leak_corr_A_masked\",\n", - " \"SP_v1.4.6_leak_corr_A_masked\"\n", - "] #Root name of the cosmosis data vector used\n", - "labels = [\"No leakage correction\", \"With leakage correction\"]\n", - "colors = [\"C0\", \"C1\"]" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "id": "866113d1", - "metadata": {}, - "outputs": [], - "source": [ - "data_vectors = []\n", - "\n", - "for root in roots:\n", - " data_vectors.append(\n", - " fits.open(data_path + root +f\"/cosmosis_{root}.fits\")\n", - " )" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "id": "ebbc442d", - "metadata": {}, - "outputs": [], - "source": [ - "#Create dummy rho and tau stat handler.\n", - "\n", - "#Inference of the xi_sys parameters\n", - "sep_units = 'arcmin'\n", - "coord_units = 'degrees'\n", - "theta_min = 1.0\n", - "theta_max = 250\n", - "nbins = 20\n", - "\n", - "\n", - "TreeCorrConfig_xi = {\n", - " 'ra_units': coord_units,\n", - " 'dec_units': coord_units,\n", - " 'min_sep': theta_min,\n", - " 'max_sep': theta_max,\n", - " 'sep_units': sep_units,\n", - " 'nbins': nbins,\n", - " 'var_method':'jackknife',\n", - "}\n", - "\n", - "rho_stats_handler = RhoStat(\n", - " output='.',\n", - " treecorr_config=TreeCorrConfig_xi,\n", - " verbose=True\n", - ")\n", - "\n", - "tau_stats_handler = TauStat(\n", - " catalogs=rho_stats_handler.catalogs,\n", - " output='.',\n", - " treecorr_config=TreeCorrConfig_xi,\n", - " verbose=True\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "id": "8f0a3808", - "metadata": {}, - "outputs": [], - "source": [ - "#Write a function to load the covariance and cut it to only use alpha and beta\n", - "def load_matrix_and_cut(root, root_cosmo_val, type='rho'):\n", - " if type=='rho':\n", - " cov = np.load(f\"{root}/cov_rho_{root_cosmo_val}.npy\")\n", - " nbins = cov.shape[0] // 6\n", - " cov = cov[:nbins*3, :nbins*3]\n", - " np.save(f\"{root}/cov_rho_{root_cosmo_val}_cut.npy\", cov)\n", - " elif type=='tau':\n", - " cov = np.load(f\"{root}/cov_tau_{root_cosmo_val}_th.npy\")\n", - " nbins = cov.shape[0] // 3\n", - " cov = cov[:nbins*2, :nbins*2]\n", - " np.save(f\"{root}/cov_tau_{root_cosmo_val}_th_cut.npy\", cov)\n", - " else:\n", - " raise ValueError(\"type must be 'rho' or 'tau'\")" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "id": "4b203d60", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Class created. Don't forget to load your rho and tau statistics and define your prior and your likelihood.\n", - "Sampling PSF parameters for No leakage correction\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "100%|██████████| 10000/10000 [00:35<00:00, 284.72it/s]\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Number of samples: 10000\n", - "\n", - "Parameters constraints\n", - "----------------------\n", - "Parameter: $\\alpha$=0.0222^+0.0026_0.0026\n", - "Parameter: $\\beta$=0.7703^+0.1131_0.1144\n", - "Chi square: 72.57480636040468\n", - "Removed no burn in\n", - "Sampling PSF parameters for With leakage correction\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "100%|██████████| 10000/10000 [00:33<00:00, 298.71it/s]" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Number of samples: 10000\n", - "\n", - "Parameters constraints\n", - "----------------------\n", - "Parameter: $\\alpha$=0.0050^+0.0021_0.0021\n", - "Parameter: $\\beta$=0.8063^+0.1082_0.1144\n", - "Chi square: 70.17303691323765\n", - "Removed no burn in\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\n" - ] - } - ], - "source": [ - "#Create a PSFErrorFit instance\n", - "psf_fitter = PSFErrorFit(rho_stats_handler, tau_stats_handler, path_cosmo_val+'rho_tau_stats/', use_eta=False)\n", - "\n", - "chains = []\n", - "\n", - "#Load rho-, tau-statistics, and cov_tau from the data_vector\n", - "for i, root_cosmo_val in enumerate(versions):\n", - " print(\"Sampling PSF parameters for \", labels[i])\n", - " path_rho = f\"rho_stats_{root_cosmo_val}.fits\"\n", - " path_tau = f\"tau_stats_{root_cosmo_val}.fits\"\n", - " path_cov_rho = f\"cov_rho_{root_cosmo_val}.npy\"\n", - " path_cov_tau = f\"cov_tau_{root_cosmo_val}_th.npy\"\n", - "\n", - " load_matrix_and_cut(path_cosmo_val+'/rho_tau_stats/', root_cosmo_val, type='rho')\n", - " load_matrix_and_cut(path_cosmo_val+'/rho_tau_stats/', root_cosmo_val, type='tau')\n", - " path_cov_rho = f\"cov_rho_{root_cosmo_val}_cut.npy\"\n", - " path_cov_tau = f\"cov_tau_{root_cosmo_val}_th_cut.npy\"\n", - "\n", - " psf_fitter.load_rho_stat(path_rho)\n", - " psf_fitter.load_tau_stat(path_tau)\n", - " psf_fitter.load_covariance(path_cov_rho, cov_type='rho')\n", - " psf_fitter.load_covariance(path_cov_tau, cov_type='tau')\n", - " samples_lq, _, _ = psf_fitter.get_least_squares_params_samples(npatch=None, apply_debias=False)\n", - "\n", - " samples_gd = MCSamples(samples=samples_lq, names=[r\"\\alpha\", r\"\\beta\"], labels=[r\"\\alpha\", r\"\\beta\"])\n", - "\n", - " chains.append(samples_gd)" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "id": "0845ac4a", - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/home/guerrini/.conda/envs/sp_validation_3.11/lib/python3.11/site-packages/getdist/plots.py:3347: UserWarning: This figure includes Axes that are not compatible with tight_layout, so results might be incorrect.\n", - " self.fig.savefig(fname, bbox_extra_artists=self.extra_artists, bbox_inches='tight', **kwargs)\n", - "/home/guerrini/.conda/envs/sp_validation_3.11/lib/python3.11/site-packages/IPython/core/events.py:82: UserWarning: This figure includes Axes that are not compatible with tight_layout, so results might be incorrect.\n", - " func(*args, **kwargs)\n", - "/home/guerrini/.conda/envs/sp_validation_3.11/lib/python3.11/site-packages/IPython/core/pylabtools.py:170: UserWarning: This figure includes Axes that are not compatible with tight_layout, so results might be incorrect.\n", - " fig.canvas.print_figure(bytes_io, **kw)\n" - ] - }, - { - "data": { - "image/png": "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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "g = plots.get_subplot_plotter()\n", - "\n", - "g.settings.legend_fontsize = 10\n", - "g.settings.axes_fontsize=10\n", - "\n", - "markers = {\n", - " r\"\\alpha\": 0.0,\n", - " r\"\\beta\": 1.0,\n", - "}\n", - "\n", - "line_args = [\n", - " {'color': colors[i]} for i in range(len(versions))\n", - "]\n", - "g.triangle_plot(\n", - " chains,\n", - " filled=True,\n", - " legend_labels=labels,\n", - " legend_loc=\"upper right\",\n", - " line_args=line_args,\n", - " contour_colors=colors,\n", - " markers=markers\n", - ")\n", - "\n", - "ax = g.get_axes(ax=(1, 0))\n", - "ax.minorticks_on()\n", - "ax = g.get_axes(ax=(1, 1))\n", - "ax.minorticks_on()\n", - "ax.get_yaxis().set_visible(False)\n", - "g.export(\"./plots/psf_leakage_prior.pdf\")" - ] - }, - { - "cell_type": "code", - "execution_count": 24, - "id": "0f1ec511", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Predicting xi_sys for No leakage correction\n", - "Predicting xi_sys for With leakage correction\n", - "Class created. Don't forget to load your rho and tau statistics and define your prior and your likelihood.\n", - "Predicting xi_sys with eta for No leakage correction\n", - "Predicting xi_sys with eta for With leakage correction\n" - ] - } - ], - "source": [ - "# Check that the prediction for the xi_sys is consistent with the (alpha, beta, eta) fit\n", - "xi_sys_samples = []\n", - "for i, root_cosmo_val in enumerate(versions):\n", - " print(\"Predicting xi_sys for \", labels[i])\n", - " samples = chains[i].samples\n", - "\n", - " path_rho = f\"rho_stats_{root_cosmo_val}.fits\"\n", - " path_tau = f\"tau_stats_{root_cosmo_val}.fits\"\n", - " \n", - " psf_fitter.load_rho_stat(path_rho)\n", - " psf_fitter.load_tau_stat(path_tau)\n", - "\n", - " xi_sys_sample = np.array([\n", - " psf_fitter.compute_xi_psf_sys(sample) for sample in samples\n", - " ])\n", - "\n", - " xi_sys_samples.append(xi_sys_sample)\n", - "\n", - "xi_sys_samples_eta = []\n", - "psf_fitter_eta = PSFErrorFit(\n", - " rho_stats_handler, tau_stats_handler, path_cosmo_val+'rho_tau_stats/', use_eta=True\n", - ")\n", - "for i, root_cosmo_val in enumerate(versions):\n", - " print(\"Predicting xi_sys with eta for \", labels[i])\n", - " # Load the saved samples\n", - " samples_eta = np.load(f\"{path_cosmo_val}/rho_tau_stats/samples_{root_cosmo_val}.npy\")\n", - "\n", - " # Load the rho and tau statistics\n", - " path_rho = f\"rho_stats_{root_cosmo_val}.fits\"\n", - " path_tau = f\"tau_stats_{root_cosmo_val}.fits\"\n", - " \n", - " psf_fitter.load_rho_stat(path_rho)\n", - " psf_fitter.load_tau_stat(path_tau)\n", - "\n", - " # Compute the xi_sys\n", - " xi_sys_sample_eta = np.array([\n", - " psf_fitter_eta.compute_xi_psf_sys(sample) for sample in samples_eta\n", - " ])\n", - " xi_sys_samples_eta.append(xi_sys_sample_eta)\n" - ] - }, - { - "cell_type": "code", - "execution_count": 34, - "id": "18c7071a", - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "plt.figure()\n", - "\n", - "#offset of the points\n", - "offset = 0.08\n", - "\n", - "for i, label in enumerate(labels):\n", - " xi_sys_low, xi_sys_med, xi_sys_up = np.quantile(\n", - " xi_sys_samples[i], [0.16, 0.5, 0.84], axis=0\n", - " )\n", - "\n", - " xi_sys_eta_low, xi_sys_eta_med, xi_sys_eta_up = np.quantile(\n", - " xi_sys_samples_eta[i], [0.16, 0.5, 0.84], axis=0\n", - " )\n", - "\n", - " theta_bins = rho_stats_handler.rho_stats['theta']\n", - "\n", - " jittered_theta = theta_bins * (1 + offset)\n", - "\n", - " plt.errorbar(\n", - " theta_bins,\n", - " xi_sys_med,\n", - " yerr=[xi_sys_low, xi_sys_up],\n", - " label=f\"{label} (no eta)\",\n", - " fmt='o',\n", - " capsize=3,\n", - " markersize=5,\n", - " alpha=0.7\n", - " )\n", - "\n", - " plt.errorbar(\n", - " jittered_theta,\n", - " xi_sys_eta_med,\n", - " yerr=[xi_sys_eta_low, xi_sys_eta_up],\n", - " label=f\"{label} (with eta)\",\n", - " fmt='s',\n", - " capsize=3,\n", - " markersize=5,\n", - " alpha=0.7\n", - " )\n", - "\n", - "plt.xlabel(\"Theta [arcmin]\")\n", - "plt.ylabel(\"xi_sys\")\n", - "\n", - "plt.xscale('log')\n", - "plt.yscale('log')\n", - "\n", - "plt.legend()\n", - "\n", - "plt.savefig(\"./plots/xi_sys_prediction_vs_eta.png\")\n", - "plt.show()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "131802b8", - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "sp_validation_3.11", - "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.11.0" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/cosmo_inference/notebooks/2D_cosmic_shear_paper_plots/2026_01_05_get_bestfit_glass_mock.py b/cosmo_inference/notebooks/2D_cosmic_shear_paper_plots/2026_01_05_get_bestfit_glass_mock.py deleted file mode 100644 index 198de3de..00000000 --- a/cosmo_inference/notebooks/2D_cosmic_shear_paper_plots/2026_01_05_get_bestfit_glass_mock.py +++ /dev/null @@ -1,256 +0,0 @@ -# %% -import os -import configparser -import subprocess - -from IPython import get_ipython - -ipython = get_ipython() - -if ipython is not None: - ipython.run_line_magic("load_ext", "autoreload") - ipython.run_line_magic("autoreload", "2") - -import numpy as np -from astropy.io import fits -import scipy.stats as stats - -import matplotlib.pyplot as plt -import seaborn as sns -from tqdm import tqdm - -from getdist import plots, MCSamples - -plt.style.use( - './matplotlib_config/paper.mplstyle' -) - -sns.set_palette("husl") - -if ipython is not None: - ipython.run_line_magic("matplotlib", "inline") - -g = plots.get_subplot_plotter(width_inch=30) -g.settings.axes_fontsize=30 -g.settings.axes_labelsize=30 -g.settings.alpha_filled_add = 0.7 -g.settings.legend_fontsize = 40 - -# %% -root_dir = "/n09data/guerrini/glass_mock_chains/" -chain_version = "v2" # choose v0 or v1 -assert chain_version in ["v0", "v1", "v2"], "Invalid chain version" - -#Path to the ini config files -path_ini_files = f'/home/guerrini/sp_validation/cosmo_inference/cosmosis_config/glass_mocks_{chain_version}/' - -# Create the list of mocks -max_sim = 12 -roots = [f"glass_mock_{chain_version}_{str(i).zfill(5)}" for i in range(1, max_sim + 1)] -lower_boud_xi = 12.0 -upper_bound_xi = 83.0 - -run_best_fit_type = "average" # should be in ["map", "average"] -assert run_best_fit_type in ["map", "average"], "Invalid best fit type" - -# %% -# Retrieve the chains -for root in roots: - with open(root_dir + '{}/{}/samples_{}.txt'.format(root, root, root)) as file: - params = file.readline()[1:].split('\t')[:-4] - file.close() - - with open(root_dir + '{}/{}/getdist_{}.paramnames'.format(root, root, root), "w") as file: - for i in range(len(params)): - if len(params[i].split('--')) > 1: - file.write(params[i].split('--')[1] + '\n') - else: - file.write(params[i].split('--')[0] + '\n') - file.close() - -# Read chain -chains=[] - -for root in roots: - - samples = np.loadtxt(root_dir + '{}/{}/samples_{}.txt'.format(root,root,root)) - print(len(samples)) - if 'nautilus' in root: - samples = np.column_stack((np.exp(samples[:,-3]),samples[:,-1]-samples[:,-2],samples[:,0:-3])) - else: - samples = np.column_stack((samples[:,-1],samples[:,-3],samples[:,0:-4])) - np.savetxt(root_dir + '{}/{}/getdist_{}.txt'.format(root,root,root), samples) - - chain = g.samples_for_root(root_dir + '{}/{}/getdist_{}'.format(root,root,root), - cache=False, - settings={'ignore_rows':0, - 'smooth_scale_2D':0.3, - 'smooth_scale_1D':0.3}) - - chains.append(chain) - -# %% -name_list = ['OMEGA_M','ombh2','h0','n_s','SIGMA_8','s_8_input', 'logt_agn','a','m1','bias_1', 'alpha', 'beta'] -label_list = ['\Omega_m', '\omega_b h^2', 'h_0', 'n_s', '\sigma_8', 'S_8', 'log T_{AGN}', 'A_{IA}', 'm_1', '\Delta z_1', '\\alpha_{PSF}', '\\beta_{PSF}'] - -for chain in chains: - param_names = chain.getParamNames() - for name, label in zip(name_list, label_list): - param_names.parWithName(name).label = label - -# %% -#Extract the best fit parameters -best_fit = {} - -for root, chain in zip(roots, chains): - print(root) - likestats = chain.getLikeStats() - bestfit_idx = np.argmax(chain.loglikes) - maxlike = chain.loglikes[bestfit_idx] - print(f"Maximum Likelihood: {maxlike:.5g}") - best_fit[root] = { - 'likelihood': maxlike - } - margestats = chain.getMargeStats() - s8_stats = margestats.parWithName('S_8') - sigma8_stats = margestats.parWithName('SIGMA_8') - omegam_stats = margestats.parWithName('OMEGA_M') - a_ia_stats = margestats.parWithName('a') - - best_fit[root].update({ - 'S_8_mean': s8_stats.mean, - 'S_8_lower': s8_stats.mean - s8_stats.limits[0].lower, - 'S_8_upper': s8_stats.limits[0].upper - s8_stats.mean, - 'sigma_8_mean': sigma8_stats.mean, - 'sigma_8_lower': sigma8_stats.mean - sigma8_stats.limits[0].lower, - 'sigma_8_upper': sigma8_stats.limits[0].upper - sigma8_stats.mean, - 'omega_m_mean': omegam_stats.mean, - 'omega_m_lower': omegam_stats.mean - omegam_stats.limits[0].lower, - 'omega_m_upper': omegam_stats.limits[0].upper - omegam_stats.mean, - 'A_IA_mean': a_ia_stats.mean, - 'A_IA_lower': a_ia_stats.mean - a_ia_stats.limits[0].lower, - 'A_IA_upper': a_ia_stats.limits[0].upper - a_ia_stats.mean - }) - try: - t_agn_stats = margestats.parWithName('logt_agn') - best_fit[root].update({ - 'logt_agn_mean': t_agn_stats.mean, - 'logt_agn_lower': t_agn_stats.mean - t_agn_stats.limits[0].lower, - 'logt_agn_upper': t_agn_stats.limits[0].upper - t_agn_stats.mean - }) - except: - pass - for i, par in enumerate(likestats.names): - if run_best_fit_type == "average": - best_fit[root].update({par.name: np.average(chain.samples[:, i], weights=chain.weights)}) - elif run_best_fit_type == "map": - best_fit[root].update({par.name: chain.samples[:, i][bestfit_idx]}) - else: - raise ValueError("Invalid run_best_fit_type") - - - -# %% -# Run CosmoSis in test mode to get the data vectors - -if not os.path.exists(path_ini_files+'/values_empty.ini'): - content = """[cosmological_parameters] - -tau = 0.0544 -w = -1.0 -massive_nu = 1 -massless_nu = 2.046 -omega_k = 0.0 -wa = 0.0 - -[halo_model_parameters] - -[intrinsic_alignment_parameters] - -[shear_calibration_parameters] - -[nofz_shifts] - -[psf_leakage_parameters] -""" - - with open(path_ini_files+'/values_empty.ini', 'w') as f: - f.write(content) - f.close() - - print('File created successfully') - -section_map = { - 'omch2': 'cosmological_parameters', - 'ombh2': 'cosmological_parameters', - 'h0': 'cosmological_parameters', - 'n_s': 'cosmological_parameters', - 's_8_input': 'cosmological_parameters', - 'logt_agn': 'halo_model_parameters', - 'a': 'intrinsic_alignment_parameters', - 'm1': 'shear_calibration_parameters', - 'bias_1': 'nofz_shifts', - 'alpha': 'psf_leakage_parameters', - 'beta': 'psf_leakage_parameters', -} - -env = os.environ.copy() -env["LD_LIBRARY_PATH"] = "/home/guerrini/.conda/envs/sp_validation_3.11/lib/python3.11/site-packages/cosmosis/datablock:" + env.get("LD_LIBRARY_PATH", "") - -os.chdir('/home/guerrini/sp_validation/cosmo_inference/') - -for idx, root in enumerate(roots): - print(root) - config = configparser.ConfigParser() - config.optionxform = str # Preserve case sensitivity of option names - config.read(path_ini_files+'/values_empty.ini') - for param, value in best_fit[root].items(): - section = section_map.get(param) - if section is None: - continue - if section not in config: - config.add_section(section) - config[section][param] = str(value) - - with open(path_ini_files+'/values_empty.ini', 'w') as configfile: - config.write(configfile) - - #Modify the ini file to run in test mode at the best fit - config = configparser.ConfigParser() - config.optionxform = str # Preserve case sensitivity of option names - config_file_path = path_ini_files+f'/cosmosis_pipeline_glass_mocks_{chain_version}_glass_mock_{str(idx+1).zfill(5)}.ini' - config.read(config_file_path) - sampler = config['runtime']['sampler'] - config['runtime']['sampler'] = 'test' - values = config['pipeline']['values'] - config['pipeline']['values'] = path_ini_files + '/values_empty.ini' - if run_best_fit_type == "map": - config['test']['save_dir'] = f"%(SCRATCH)s/best_fit/{root}_map" - elif run_best_fit_type == "average": - config['test']['save_dir'] = f"%(SCRATCH)s/best_fit/{root}" - else: - raise ValueError("Invalid run_best_fit_type") - - - with open(config_file_path, 'w') as configfile: - config.write(configfile) - - #Run cosmosis - result = subprocess.run( - ['cosmosis', config_file_path], - env=env, - capture_output=True, - text=True - ) - print(f"STDOUT:\n{result.stdout}") - print(f"STDERR:\n{result.stderr}") - - #Modify the ini file to the previous one - config['pipeline']['values'] = values - config['runtime']['sampler'] = sampler - if run_best_fit_type == "map": - config['test']['save_dir'] = f"%(SCRATCH)s/best_fit/{root}" - - with open(config_file_path, 'w') as configfile: - config.write(configfile) -# %% diff --git a/cosmo_inference/notebooks/2D_cosmic_shear_paper_plots/2026_01_05_get_p_value_glass_mock.py b/cosmo_inference/notebooks/2D_cosmic_shear_paper_plots/2026_01_05_get_p_value_glass_mock.py deleted file mode 100644 index fde947c9..00000000 --- a/cosmo_inference/notebooks/2D_cosmic_shear_paper_plots/2026_01_05_get_p_value_glass_mock.py +++ /dev/null @@ -1,277 +0,0 @@ -# %% -import os - -#Trick to use latex in the plots -os.environ["LD_LIBRARY_PATH"] = "" -os.environ["CONDA_PREFIX"] = "/home/guerrini/.conda/envs/phd_manuscript" - -from IPython import get_ipython - -ipython = get_ipython() - -if ipython is not None: - ipython.run_line_magic("load_ext", "autoreload") - ipython.run_line_magic("autoreload", "2") - -import numpy as np -from astropy.io import fits -import scipy.stats as stats -from scipy.interpolate import interp1d - -import matplotlib.pyplot as plt -from matplotlib import scale as mscale -import seaborn as sns -from tqdm import tqdm - -from sp_validation.utils_cosmo_val import SquareRootScale - -mscale.register_scale(SquareRootScale) - -from getdist import plots, MCSamples - -plt.style.use( - './matplotlib_config/paper.mplstyle' -) - -sns.set_palette("husl") - -if ipython is not None: - ipython.run_line_magic("matplotlib", "inline") - -# %% -root_glass_chains = "/n09data/guerrini/glass_mock_chains/" - -# Version of the glass mock chain run -chain_version = "v2" -assert chain_version in ["v0", "v1", "v2"] - -# Path to the glass mock data vectors -root_glass_dv = f"/home/guerrini/sp_validation/cosmo_inference/data/glass_mocks/{chain_version}/" - -# Create the list of mocks -max_sim = 12 -roots_glass_mock = [f"glass_mock_{chain_version}_{str(i).zfill(5)}" for i in range(1, max_sim + 1)] - -lower_bound_xi_ee = 12.0 -upper_bound_xi_ee = 83.0 - -# %% -def get_chi2_glass_mock(root, root_glass_chains, root_glass_dv, lower_bound_xi_plus, upper_bound_xi_plus, lower_bound_xi_minus, upper_bound_xi_minus): - #Read the theory prediction at best fit - theta = np.loadtxt(f"{root_glass_chains}/{root}/best_fit/{root}/shear_xi_plus/theta.txt") - theta_arcmin = theta * 180 * 60 /np.pi - shear_xi_plus = np.loadtxt(f"{root_glass_chains}/{root}/best_fit/{root}/shear_xi_plus/bin_1_1.txt") - shear_xi_minus = np.loadtxt(f"{root_glass_chains}/{root}/best_fit/{root}/shear_xi_minus/bin_1_1.txt") - xi_sys_plus = np.loadtxt(f"{root_glass_chains}/{root}/best_fit/{root}/xi_sys/shear_xi_plus.txt") - xi_sys_minus = np.loadtxt(f"{root_glass_chains}/{root}/best_fit/{root}/xi_sys/shear_xi_minus.txt") - - #Read the data - idx = root.replace(f"glass_mock_{chain_version}_", "") - chain_version_data = "v0" if chain_version in ["v0", "v1"] else "v2" - data = fits.open(f"{root_glass_dv}/glass_mock_{idx}/cosmosis_glass_mock_{chain_version_data}_{idx}.fits") - - theta_data = data["XI_PLUS"].data["ANG"] - xi_plus_data = data["XI_PLUS"].data["VALUE"] - xi_minus_data = data["XI_MINUS"].data["VALUE"] - - # Load the covariance - cov = data["COVMAT"].data - cov_xi = cov[0:2*len(xi_plus_data), 0:2*len(xi_plus_data)] - - # Interpolate the model - interp_xi_plus = interp1d(theta_arcmin, shear_xi_plus, kind='cubic', fill_value='extrapolate') - interp_xi_minus = interp1d(theta_arcmin, shear_xi_minus, kind='cubic', fill_value='extrapolate') - - xi_plus_model = interp_xi_plus(theta_data) + xi_sys_plus - xi_minus_model = interp_xi_minus(theta_data) + xi_sys_minus - - xi_data = np.concatenate((xi_plus_data, xi_minus_data)) - xi_model = np.concatenate((xi_plus_model, xi_minus_model)) - - # Apply scale cuts - mask_xi_plus = (theta_data > lower_bound_xi_plus) & (theta_data < upper_bound_xi_plus) - mask_xi_minus = (theta_data > lower_bound_xi_minus) & (theta_data < upper_bound_xi_minus) - mask = np.concatenate((mask_xi_plus, mask_xi_minus)) - - xi_data = xi_data[mask] - xi_model = xi_model[mask] - cov_xi = cov_xi[mask][:, mask] - - xi_chi2 = np.dot((xi_model - xi_data), np.dot(np.linalg.inv(cov_xi), (xi_model - xi_data))) - - return xi_chi2 - -def get_chi2_map_glass_mock(root, root_glass_chains): - path_sim = f"{root_glass_chains}/{root}/{root}/samples_{root}.txt" - samples = np.loadtxt(path_sim) - xi_chi2_map = samples[-1, -3] - - return -2*xi_chi2_map - -# %% -metrics = {} - -for i, root in enumerate(roots_glass_mock): - metrics[root] = {} - metrics[root]["chi2"] = get_chi2_glass_mock(root, root_glass_chains, root_glass_dv, lower_bound_xi, upper_bound_xi, lower_bound_xi, upper_bound_xi) - metrics[root]["chi2_map"] = get_chi2_map_glass_mock(root, root_glass_chains) - -# %% -chi2_glass_mocks = np.array([metrics[root]["chi2"] for root in roots_glass_mock]) -chi2_glass_mocks_map = np.array([metrics[root]["chi2_map"] for root in roots_glass_mock]) - -sns.histplot( - chi2_glass_mocks, - bins=25, - kde=False, - stat='density' -) - -sns.histplot( - chi2_glass_mocks_map, - bins=25, - kde=False, - stat='density' -) - -k = 8 -x = np.linspace(8, 70) -chi2 = stats.chi2.pdf(x, k) - -plt.plot(x, chi2, c='k') - -plt.xlabel(r"$\chi^2$") - -plt.show() -# %% -def plot_glass_mock_fit_root(root, root_glass_chains, root_glass_dv): - #Read the theory prediction at best fit - ell = np.loadtxt(f"{root_glass_chains}/{root}/best_fit/{root}_cell/shear_cl/ell.txt") - shear_cl = np.loadtxt(f"{root_glass_chains}/{root}/best_fit/{root}_cell/shear_cl/bin_1_1.txt") - - ell_map = np.loadtxt(f"{root_glass_chains}/{root}/best_fit/{root}_cell_map/shear_cl/ell.txt") - shear_cl_map = np.loadtxt(f"{root_glass_chains}/{root}/best_fit/{root}_cell_map/shear_cl/bin_1_1.txt") - - #Read the data - idx = root.replace(f"glass_mock_{chain_version}_", "") - chain_version_data = "v0" if chain_version in ["v0", "v1"] else "v2" - data = fits.open(f"{root_glass_dv}/glass_mock_{idx}/cosmosis_glass_mock_{chain_version_data}_{idx}.fits") - - ell_data = data["CELL_EE"].data["ANG"] - cell_data = data["CELL_EE"].data["VALUE"] - - fig = plt.figure() - - plt.errorbar( - ell_data, - ell_data*cell_data, - yerr=ell_data*np.sqrt(data["COVMAT"].data.diagonal()[80:]), - fmt='o', - label='Data', - alpha=0.5 - ) - - plt.plot( - ell, - ell*shear_cl, - label='Best-fit model', - c='r' - ) - - plt.plot( - ell_map, - ell_map*shear_cl_map, - label='Best-fit model (map)', - c='orange' - ) - - plt.axvline(300) - plt.axvline(1600) - - plt.xlim(0, 2048) - plt.ylim(bottom=0.5e-7) - plt.xlabel(r"$\ell$") - plt.ylabel(r"$C_\ell^{EE}$") - plt.xscale('squareroot') - plt.legend() - - return fig - -# %% -fig = plot_glass_mock_fit_root(roots_glass_mock[10], root_glass_chains, root_glass_dv) - -plt.legend() - -plt.show() -# %% -idx_sim = 1 -idx_sim = str(idx_sim).zfill(5) - -path_first_run = "/n09data/guerrini/glass_mock_v1.4.6/results/" -path_second_run = "/n09data/guerrini/glass_mock_v1.4.6_rerun/results/" -first_run = np.load( - f"{path_first_run}/cl_glass_mock_{idx_sim}_4096.npy" -) -second_run = np.load( - f"{path_second_run}/cl_glass_mock_{idx_sim}_4096.npy" -) - -chain_version_data = "v0" if chain_version in ["v0", "v1"] else "v2" -data = fits.open(f"{root_glass_dv}/glass_mock_{idx_sim}/cosmosis_glass_mock_{chain_version_data}_{idx_sim}.fits") - -plt.figure() - -plt.errorbar( - first_run[0], - first_run[0] * first_run[1], - yerr=first_run[0] * np.sqrt(data["COVMAT"].data.diagonal()[80:]), - fmt='o', - label='First run', - alpha=0.5 -) - -plt.errorbar( - second_run[0], - second_run[0] * second_run[1], - yerr=second_run[0] * np.sqrt(data["COVMAT"].data.diagonal()[80:]), - fmt='o', - label='Second run', - alpha=0.5 -) - -plt.xscale('squareroot') -plt.legend() - -plt.show() - -# %% -first_run_cls = [] -second_run_cls = [] -for i in range(1, 351): - idx_sim = str(i).zfill(5) - - path_first_run = "/n09data/guerrini/glass_mock_v1.4.6/results/" - path_second_run = "/n09data/guerrini/glass_mock_v1.4.6_rerun/results/" - first_run = np.load( - f"{path_first_run}/cl_glass_mock_{idx_sim}_4096.npy" - ) - second_run = np.load( - f"{path_second_run}/cl_glass_mock_{idx_sim}_4096.npy" - ) - - first_run_cls.append(first_run[1]) - second_run_cls.append(second_run[1]) -# %% -cov_first_run = np.cov(np.array(first_run_cls).T) -cov_second_run = np.cov(np.array(second_run_cls).T) - -# %% -plt.figure() - -plt.plot(np.sqrt(cov_first_run.diagonal())) -plt.plot(np.sqrt(cov_second_run.diagonal())) - -plt.yscale('log') -plt.show() - -# %% diff --git a/cosmo_inference/notebooks/2D_cosmic_shear_paper_plots/S8_sigma8_Om_contour.ipynb b/cosmo_inference/notebooks/2D_cosmic_shear_paper_plots/S8_sigma8_Om_contour.ipynb deleted file mode 100644 index 455e37c9..00000000 --- a/cosmo_inference/notebooks/2D_cosmic_shear_paper_plots/S8_sigma8_Om_contour.ipynb +++ /dev/null @@ -1,266 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "510c4e0b", - "metadata": {}, - "source": [ - "## $S_8 - \\Omega_m$ and $\\sigma_8-\\Omega_m$ Contour Plot\n", - "\n", - "This notebook creates a 2D marginalised contour plot of the $S_8$ and $\\Omega_m$ parameters, comparing this work with fiducial results from DES Y3, HSC and KiDS-Legacy (no chains yet so maybe just KiDS-1000?). Also the same for a plot of $\\sigma_8-\\Omega_m$.\n", - "\n", - "This notebook also reds the chains and derives the posterior values of $S_8$, subsequently writing them intoa file to be read in and plotted as a whisker plot in S8_whisker.ipynb." - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "id": "5e65319a-63f3-47d7-90cd-7b7db06174e9", - "metadata": {}, - "outputs": [], - "source": [ - "from getdist import plots, loadMCSamples\n", - "import numpy as np\n", - "import matplotlib.pyplot as plt\n", - "import uncertainties\n", - "import os\n", - "\n", - "plt.rcParams.update({\"text.usetex\": True})\n", - "\n", - "g = plots.get_subplot_plotter(width_inch=12)\n", - "g.settings.axes_fontsize=30\n", - "g.settings.axes_labelsize=40\n", - "g.settings.alpha_filled_add = 0.7\n", - "g.settings.legend_fontsize = 20\n", - "\n", - "%matplotlib inline\n", - "\n", - "#SPECIFY DATA DIRECTORY AND DESIRED CHAINS TO ANALYSE\n", - "root_dir='/n23data1/n06data/lgoh/scratch/UNIONS/chains/ext_data'\n", - "roots = [\n", - " 'DES_Y3',\n", - " 'HSC_Y3',\n", - " 'DES+KiDS',\n", - " 'KiDS-1000',\n", - " 'Planck18'\n", - " ]\n", - "\n", - "root_label = [\n", - " r'DES Y3 ($\\xi_\\pm$)',\n", - " r'HSC Y3 ($\\xi_\\pm$)',\n", - " r'DES+KiDS ($\\xi_\\pm$)',\n", - " r'KiDS-1000 ($\\xi_\\pm$)',\n", - " r'Planck18 TT+TE+EE+lowE'\n", - " ]\n" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "ba84564b", - "metadata": {}, - "outputs": [], - "source": [ - "# Create the .paramnames file needed by getdist (take the parameter names from the first line of the output file)\n", - "for root in roots:\n", - " if os.path.isfile(f\"{root_dir}/{root}/getdist_{root}.paramnames\")==False:\n", - " \n", - " with open(f\"{root_dir}/{root}/{root}.txt\", \"r\") as file:\n", - " params = file.readline()[1:].split('\\t')[:-4]\n", - " file.close()\n", - " \n", - " with open(f\"{root_dir}/{root}/getdist_{root}.paramnames\", \"w\") as file:\n", - " for i in range(len(params)):\n", - " if len(params[i].split('--')) > 1:\n", - " file.write(params[i].split('--')[1] + '\\n')\n", - " else:\n", - " file.write(params[i].split('--')[0] + '\\n')\n", - " file.close()\n", - " print(params)" - ] - }, - { - "cell_type": "markdown", - "id": "70549903-a160-4a3e-a202-bd5a9d6b45eb", - "metadata": {}, - "source": [ - "## Retrieve the chains" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "id": "4795888c-ce6f-4fe2-bbd4-fe17b5e57f02", - "metadata": {}, - "outputs": [], - "source": [ - "#READ CHAIN\n", - "\n", - "chains=[]\n", - "\n", - "for root in roots:\n", - " if os.path.isfile(f\"{root_dir}/{root}/getdist_{root}.paramnames\")==False:\n", - " samples = np.loadtxt(f\"{root_dir}/{root}/{root}.txt\")\n", - " samples = np.column_stack((samples[:,-1],samples[:,-3],samples[:,0:-4]))\n", - " np.savetxt(f\"{root_dir}/{root}/getdist_{root}.txt\", samples)\n", - " \n", - " chain = g.samples_for_root(f\"{root_dir}/{root}/getdist_{root}\",\n", - " cache=False,\n", - " settings={'ignore_rows':0,\n", - " # 'smooth_scale_2D':0.7,\n", - " # 'smooth_scale_1D':0.7\n", - " })\n", - " p = chain.getParams()\n", - " chain.addDerived(p.omega_m, name='OMEGA_M', label=r'$\\Omega_m$')\n", - " chain.addDerived(p.SIGMA_8, name='sigma_8', label=r'$\\sigma_8$')\n", - " if hasattr(p,'S_8')==False:\n", - " chain.addDerived(p.SIGMA_8*(np.sqrt(p.omega_m/0.3)), name='S_8', label=r'S_8')\n", - "\n", - " chains.append(chain)" - ] - }, - { - "cell_type": "markdown", - "id": "09ff24ef-6e8c-4ddd-96de-eeaf63b6982d", - "metadata": {}, - "source": [ - "## Plot the chain" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "9080b714-810e-4a9d-b59d-54299752e35f", - "metadata": {}, - "outputs": [], - "source": [ - "%matplotlib inline\n", - "g.plot_2d(chains,\n", - " ['OMEGA_M','S_8'],\n", - " # contour_colors=['#0072B2', '#009E73', '#D55E00', '#CC79A7'],\n", - " filled=True)\n", - "g.add_legend(root_label, legend_loc='upper left')\n", - "# g.export('contour_plot_s8_om_fid.pdf')" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "6d627a76", - "metadata": {}, - "outputs": [], - "source": [ - "%matplotlib inline\n", - "g.plot_2d(chains,\n", - " ['OMEGA_M','sigma_8'],\n", - " # contour_colors=['#0072B2', '#009E73', '#D55E00', '#CC79A7'],\n", - " filled=True)\n", - "g.add_legend(root_label, legend_loc='upper left')\n", - "# g.export('contour_plot_sigma8_om_fid.pdf')" - ] - }, - { - "cell_type": "markdown", - "id": "d386da94-c165-488f-8604-ec2109935e07", - "metadata": { - "jp-MarkdownHeadingCollapsed": true, - "tags": [] - }, - "source": [ - "### Output bestfit and sigma values of parameters" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "1ab5f45e-9f92-422a-89ef-1453b0b1c153", - "metadata": {}, - "outputs": [], - "source": [ - "#########BESTFIT AND SIGMA VALS##########\n", - "params = ['OMEGA_M','S_8']\n", - "latex_params = [r'$\\Omega_{m}$',r'$S_8$']\n", - "\n", - "chains = chains[::-1]\n", - "for chain in chains:\n", - "\n", - " margestats = chain.getMargeStats()\n", - " likestats = chain.getLikeStats()\n", - " p=chain.getParams()\n", - "\n", - " for no in range(len(latex_params)):\n", - " if hasattr(p,params[no]):\n", - " param_stats = margestats.parWithName(params[no])\n", - " a = np.array([param_stats.mean,param_stats.mean-param_stats.limits[0].lower, param_stats.limits[0].upper-param_stats.mean])\n", - " if '%.2g' %a[1] == '%.2g' %a[2]:\n", - " latex_params[no] += '&$%.3g\\pm%.2g$'%(a[0],a[1])\n", - " else:\n", - " latex_params[no] += '&$%.3g_{-%.2g}^{+%.2g}$'%(a[0],a[1],a[2])\n", - " else:\n", - " latex_params[no] += '&$-$'\n", - "\n", - " \n", - "for param in latex_params:\n", - " param += r'\\\\'\n", - " print(param) \n" - ] - }, - { - "cell_type": "markdown", - "id": "bbf09de1", - "metadata": {}, - "source": [ - "### Save values of $S_8$" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "6cab7bbb-8ce2-4e8c-8a2d-721442d14a6f", - "metadata": {}, - "outputs": [], - "source": [ - "s8_values = np.array([\"# Expt\", \"Mean\", \"S8_low\", \"S8_high\"])\n", - "for i, chain in enumerate(chains):\n", - "\n", - " margestats = chain.getMargeStats()\n", - " likestats = chain.getLikeStats()\n", - "\n", - " param_stats = margestats.parWithName('S_8')\n", - " \n", - " s8_values = np.vstack((s8_values,[root_label[i], param_stats.mean, param_stats.mean-param_stats.limits[0].lower, param_stats.limits[0].upper-param_stats.mean]))\n", - "print(s8_values)\n", - "np.savetxt(f\"{root_dir}/S8_means.txt\", s8_values, fmt=['%s','%s','%s','%s'], delimiter=',')" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "47e60452", - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "sp-validation", - "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.9.21" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/cosmo_inference/notebooks/2D_cosmic_shear_paper_plots/S8_whisker.ipynb b/cosmo_inference/notebooks/2D_cosmic_shear_paper_plots/S8_whisker.ipynb deleted file mode 100644 index fada9ea7..00000000 --- a/cosmo_inference/notebooks/2D_cosmic_shear_paper_plots/S8_whisker.ipynb +++ /dev/null @@ -1,113 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## $S_8$ Whisker Plot\n", - "\n", - "This notebook creates a whisker plot of $S_8$ values for different test cases and external datasets." - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": {}, - "outputs": [], - "source": [ - "import matplotlib\n", - "from astropy.io import fits\n", - "import matplotlib.pyplot as plt\n", - "import uncertainties\n", - "import yaml\n", - "import os\n", - "import numpy as np\n", - "\n", - "plt.rcParams.update({\"text.usetex\": True})\n", - "plt.rcParams.update({'font.size': 25})\n", - "plt.rc('mathtext', fontset='stix')\n", - "plt.rc('font', family='serif')\n", - "\n", - "chains_dir = f\"/n23data1/n06data/lgoh/scratch/UNIONS/chains\"\n", - "num_test_cases = 1\n" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": {}, - "outputs": [], - "source": [ - "# Read in text file with s8 values for the different test cases and external experiments \n", - "# (have had to run getdist to analyse the chains first)\n", - "\n", - "s8s = np.loadtxt(f\"{chains_dir}/S8_means.txt\",dtype={'names': ('Expt', 's8_mean', 's8_low', 's8_high'), 'formats': ('U40', 'U20', 'U20', 'U20')}, skiprows=1, delimiter=',')\n", - "expt = s8s['Exp']\n", - "s8s_mean = s8s['s8_mean'].astype(np.float64)\n", - "s8s_low = s8s['s8_low'].astype(np.float64)\n", - "s8s_high = s8s['s8_high'].astype(np.float64)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "\n", - "fig, axs = plt.subplots(1, 1, sharey=True, figsize=[7,1.5*len(expt)])\n", - "axs.yaxis.set_visible(False)\n", - "\n", - "y = np.arange(0,len(expt))\n", - "\n", - "for i in y:\n", - " if i > len(expt)-num_test_cases-1:\n", - " axs.errorbar(s8s_mean[i], i+1, xerr=np.vstack((s8s_low[i],s8s_high[i])), fmt='o', c = 'darkblue',lw = 2, capsize=5,capthick=2)\n", - " else:\n", - " axs.errorbar(s8s_mean[i], i+1, xerr=np.vstack((s8s_low[i],s8s_high[i])), fmt='o', c = 'darkgreen',lw = 2, capsize=5,capthick=2)\n", - " \n", - " if i == 0: # Plot the band for \"Planck\"\n", - " axs.axvspan(s8s_mean[i]-s8s_low[i], s8s_mean[i]+s8s_high[i], alpha=0.2, color='cyan')\n", - " if i == len(expt)-1: # Plot the band for \"this work\"\n", - " axs.axvspan(s8s_mean[i]-s8s_low[i], s8s_mean[i]+s8s_high[i], alpha=0.2, color='lightpink')\n", - " if i == len(expt)-num_test_cases-1: # Make a distinction between this work (and all its test cases) with external datasets\n", - " axs.axhline(i+1.5, ls='dashed',c='k')\n", - " \n", - " \n", - " axs.set_xlabel(r'$S_8=\\sigma_8\\sqrt{\\Omega_{\\rm m}/0.3}$') \n", - " axs.text(0.62, i+1, rf\"{expt[i]}\")\n", - "\n", - "plt.ylim([0,i+2])\n", - "# plt.savefig('plots/s8_whisker.pdf',bbox_inches=\"tight\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "sp-validation", - "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.9.21" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/cosmo_inference/notebooks/2D_cosmic_shear_paper_plots/config/config.yaml b/cosmo_inference/notebooks/2D_cosmic_shear_paper_plots/config/config.yaml deleted file mode 100644 index 26020b81..00000000 --- a/cosmo_inference/notebooks/2D_cosmic_shear_paper_plots/config/config.yaml +++ /dev/null @@ -1,19 +0,0 @@ -version: SP_v1.4.6.3_leak_corr -# chain: SP_v1.4.6.3_leak_corr_?_12_83 # TODO: update when v1.4.6.3 chains available - -# Data paths -xi_data: /n17data/cdaley/unions/pure_eb/code/sp_validation/notebooks/cosmo_val/output/SP_v1.4.6.3_leak_corr_xi_minsep=1.0_maxsep=250.0_nbins=20_npatch=1.txt -# bestfit_dir: TODO — waiting for v1.4.6.3 inference chains from Lisa -bestfit_dir: /n09data/guerrini/output_chains/SP_v1.4.6_leak_corr_C_10_80/best_fit/SP_v1.4.6_leak_corr_C_10_80 -pure_eb_data: /n17data/cdaley/unions/pure_eb/results/paper_plots/intermediate/SP_v1.4.6.3_leak_corr_A_pure_eb_semianalytic.npz - -# Scale cuts (arcmin) — fiducial: [12, 83] for both xi+ and xi- -scale_min: 12 -scale_max: 83 - -# Plot style -plot_style: /n17data/cdaley/unions/pure_eb/code/sp_validation/cosmo_inference/notebooks/2D_cosmic_shear_paper_plots/config/paper.mplstyle - -# Legacy config for old rules (if needed) -ini_dirs: - - /home/guerrini/sp_validation/cosmo_inference/cosmosis_config/ diff --git a/cosmo_inference/notebooks/2D_cosmic_shear_paper_plots/config/paper.mplstyle b/cosmo_inference/notebooks/2D_cosmic_shear_paper_plots/config/paper.mplstyle deleted file mode 100644 index 07a5e0b5..00000000 --- a/cosmo_inference/notebooks/2D_cosmic_shear_paper_plots/config/paper.mplstyle +++ /dev/null @@ -1,14 +0,0 @@ -figure.titlesize : 10 -figure.titleweight : bold -figure.autolayout : True -axes.titlesize : 10 -legend.fontsize : 8 -lines.linewidth : 1.5 -lines.markersize : 4 -axes.labelsize : 10 -xtick.labelsize : 9 -ytick.labelsize : 9 -text.usetex : True -axes.formatter.use_mathtext : True -font.family : serif -font.size : 10 \ No newline at end of file diff --git a/cosmo_inference/notebooks/2D_cosmic_shear_paper_plots/corr_func.ipynb b/cosmo_inference/notebooks/2D_cosmic_shear_paper_plots/corr_func.ipynb deleted file mode 100644 index 8174aced..00000000 --- a/cosmo_inference/notebooks/2D_cosmic_shear_paper_plots/corr_func.ipynb +++ /dev/null @@ -1,331 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Correlation Function Plots\n", - "\n", - "This notebook creates all the plots of the 2 point correlation functions (2PCFs) appearing in the paper: the fiducial $\\xi_\\pm$, the $\\xi_{E/B}$ as well as the $\\xi_{sys}$ correlation functions." - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "import matplotlib\n", - "from astropy.io import fits\n", - "import matplotlib.pyplot as plt\n", - "import uncertainties\n", - "import yaml\n", - "import os\n", - "import numpy as np\n", - "\n", - "plt.rcParams.update({'font.size': 25,'figure.figsize':[12,7]})\n", - "plt.rcParams.update({\"text.usetex\": True})\n", - "plt.rc('mathtext', fontset='stix')\n", - "plt.rc('font', family='serif')\n", - "\n", - "# Define path to data files (NOTE: YOU MUST HAVE RAN THE cosmo_val.py PIPELINE!)\n", - "cosmoval_data_dir = \"/n23data1/n06data/lgoh/scratch/UNIONS/sp_validation/notebooks/cosmo_val/output\"\n", - "ver = \"SP_v1.4.5\"\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Plot the 2PCFs $\\xi_\\pm$" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Read in the text file of the 2PCFs\n", - "\n", - "xipm_fname = f\"{cosmoval_data_dir}/xi_pm_{ver}.txt\"\n", - "print(f\"Reading xi_plus's from {xipm_fname}\")\n", - "\n", - "xipm = np.loadtxt(xipm_fname)\n", - "theta = xipm[:,1]\n", - "xip = xipm[:,3]\n", - "xim = xipm[:,4]\n", - "varxip = xipm[:,7]\n", - "varxim = xipm[:,8]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "#Plot the xi_plus\n", - "ax1 = plt.subplot(111)\n", - "ax1.tick_params(axis='both', which='both', direction='in', length=6, width=1,\n", - " top=True, bottom=True, left=True, right=True)\n", - "ax1.yaxis.minorticks_on()\n", - "\n", - "# ax1.errorbar(theta, xip*1e4, yerr=varxip*1e4, \n", - "# fmt='o', markersize=6, capsize=2, capthick=1.5, ls = 'solid', lw=1.8,\n", - "# label=r'$\\xi_+$', \n", - "# color='royalblue')\n", - "ax1.plot(theta, xip*1e4, marker='o', markersize=4, ls = 'solid', lw=1.8, color=\"royalblue\")\n", - "ax1.fill_between(theta, (xip-varxip)*1e4, (xip+varxip)*1e4, color=\"powderblue\", alpha=0.7)\n", - "ax1.text(0.85 , 0.88, '1-1', transform=ax1.transAxes,\n", - " bbox=dict(facecolor='white', edgecolor='black', boxstyle='round', pad=0.5))\n", - "ax1.axvspan(0,10,color='gray', alpha=0.3)\n", - "ax1.axvspan(150,200,color='gray', alpha=0.3)\n", - "ax1.set_xscale('log')\n", - "ax1.set_xlabel(r'$\\theta$ [arcmin]')\n", - "ax1.set_ylabel(r'$\\xi_+\\times 10^4$')\n", - "# plt.savefig('plots/xi_plus_%s.pdf' %ver,bbox_inches='tight')\n", - "plt.show()\n", - "\n", - "# Plot the xi_minus\n", - "ax2 = plt.subplot(111)\n", - "ax2.tick_params(axis='both', which='both', direction='in', length=6, width=1,\n", - " top=True, bottom=True, left=True, right=True)\n", - "ax2.yaxis.minorticks_on()\n", - "\n", - "# ax2.errorbar(theta, xim*1e4, yerr=varxim*1e4, \n", - "# fmt='o', markersize=6, capsize=2, capthick=1.5, ls = 'solid', lw=1.8,\n", - "# label=r'$\\xi_-$',\n", - "# color='orangered')\n", - "ax2.plot(theta, xim*1e4, marker='o', markersize=4, ls = 'solid', lw=1.8, color=\"orangered\")\n", - "ax2.fill_between(theta, (xim-varxim)*1e4, (xim+varxim)*1e4, color=\"pink\", alpha=0.7)\n", - "ax2.text(0.85, 0.88, '1-1', transform=ax2.transAxes,\n", - " bbox=dict(facecolor='white', edgecolor='black', boxstyle='round', pad=0.5))\n", - "ax2.axvspan(0,10,color='gray', alpha=0.3)\n", - "ax2.axvspan(150,200,color='gray', alpha=0.3)\n", - "ax2.set_xscale('log')\n", - "ax2.set_xlabel(r'$\\theta$ [arcmin]')\n", - "ax2.set_ylabel(r'$\\xi_-\\times 10^4$')\n", - "# plt.savefig('plots/xi_minus_%s.pdf' %ver,bbox_inches='tight')\n", - "plt.show()\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Plot the E/B modes $\\xi_{E/B}$" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Read in the text file of the 2PCFs\n", - "\n", - "xieb_fname = f\"{cosmoval_data_dir}/xi_eb_{ver}.txt\"\n", - "print(f\"Reading xi_e/b's from {xieb_fname}\")\n", - "\n", - "xieb = np.loadtxt(xieb_fname)\n", - "theta = xieb[:,0]\n", - "xie_p = xieb[:,1]\n", - "xie_m = xieb[:,2]\n", - "xib_p = xieb[:,3]\n", - "xib_m = xieb[:,4]\n", - "xiamb_p = xieb[:,5]\n", - "xiamb_m = xieb[:,6]\n", - "\n", - "xieb_cov_fname = f\"{cosmoval_data_dir}/xi_eb_{ver}_cov.txt\"\n", - "print(f\"Reading xi_e/b covmat from {xieb_cov_fname}\")\n", - "\n", - "xieb_cov = np.loadtxt(xieb_cov_fname)\n", - "ndata = len(theta)\n", - "varxi_e_p = np.diag(xieb_cov[:ndata,:ndata])\n", - "varxi_e_m = np.diag(xieb_cov[ndata:2*ndata,ndata:2*ndata])\n", - "varxi_b_p = np.diag(xieb_cov[2*ndata:3*ndata,2*ndata:3*ndata])\n", - "varxi_b_m = np.diag(xieb_cov[3*ndata:4*ndata,3*ndata:4*ndata])\n", - "varxi_amb_p = np.diag(xieb_cov[4*ndata:5*ndata,4*ndata:5*ndata])\n", - "varxi_amb_m = np.diag(xieb_cov[5*ndata:6*ndata,5*ndata:6*ndata])\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "#Plot the xi_plus\n", - "ax1 = plt.subplot(111)\n", - "ax1.tick_params(axis='both', which='both', direction='in', length=6, width=1,\n", - " top=True, bottom=True, left=True, right=True)\n", - "ax1.yaxis.minorticks_on()\n", - "\n", - "ax1.errorbar(theta, xie_p*1e4, yerr=np.sqrt(varxi_e_p)*1e4, \n", - " fmt='o', markersize=6, capsize=3, capthick=1.5, ls = 'solid', lw=1.8,\n", - " label=r'$\\xi_E$', \n", - " color='royalblue')\n", - "ax1.errorbar(theta, xib_p*1e4, yerr=np.sqrt(varxi_b_p)*1e4, \n", - " fmt='o', markersize=6, capsize=3, capthick=1.5, ls = 'dashed', lw=1.8,\n", - " label=r'$\\xi_B$', \n", - " color='chocolate')\n", - "ax1.errorbar(theta, xiamb_p*1e4, yerr=np.sqrt(varxi_amb_p)*1e4, \n", - " fmt='o', markersize=6, capsize=3, capthick=1.5, ls = 'dotted', lw=1.8,\n", - " label=r'$\\xi_{\\rm{amb}}$', \n", - " color='mediumvioletred')\n", - "ax1.text(0.9, 0.15, '1-1', transform=ax1.transAxes,\n", - " bbox=dict(facecolor='white', edgecolor='black', boxstyle='round', pad=0.5))\n", - "ax1.axvspan(0,10,color='grey', alpha=0.3)\n", - "ax1.axvspan(150,200,color='grey', alpha=0.3)\n", - "ax1.axhline(0,color='black',lw=1,ls='dashed')\n", - "ax1.set_xscale('log')\n", - "ax1.set_xlabel(r'$\\theta$ [arcmin]')\n", - "ax1.legend()\n", - "ax1.set_ylabel(r'$\\xi_+\\times 10^4$')\n", - "# plt.savefig('plots/xi_eb_plus_%s.pdf' %ver,bbox_inches='tight')\n", - "plt.show()\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "#Plot the xi_minus\n", - "ax1 = plt.subplot(111)\n", - "ax1.tick_params(axis='both', which='both', direction='in', length=6, width=1,\n", - " top=True, bottom=True, left=True, right=True)\n", - "ax1.yaxis.minorticks_on()\n", - "\n", - "ax1.errorbar(theta, xie_m*1e4, yerr=np.sqrt(varxi_e_m)*1e4, \n", - " fmt='o', markersize=6, capsize=3, capthick=1.5, ls = 'solid', lw=1.8,\n", - " label=r'$\\xi_E$', \n", - " color='royalblue')\n", - "ax1.errorbar(theta, xib_m*1e4, yerr=np.sqrt(varxi_b_m)*1e4, \n", - " fmt='o', markersize=6, capsize=3, capthick=1.5, ls = 'dashed', lw=1.8,\n", - " label=r'$\\xi_B$', \n", - " color='chocolate')\n", - "ax1.errorbar(theta, xiamb_m*1e4, yerr=np.sqrt(varxi_amb_m)*1e4, \n", - " fmt='o', markersize=6, capsize=3, capthick=1.5, ls = 'dotted', lw=1.8,\n", - " label=r'$\\xi_{\\rm{amb}}$', \n", - " color='mediumvioletred')\n", - "ax1.text(0.9, 0.15, '1-1', transform=ax1.transAxes,\n", - " bbox=dict(facecolor='white', edgecolor='black', boxstyle='round', pad=0.5))\n", - "ax1.axvspan(0,10,color='grey', alpha=0.3)\n", - "ax1.axvspan(150,200,color='grey', alpha=0.3)\n", - "ax1.axhline(0,color='black',lw=1,ls='dashed')\n", - "ax1.set_xscale('log')\n", - "ax1.set_xlabel(r'$\\theta$ [arcmin]')\n", - "ax1.legend()\n", - "ax1.set_ylabel(r'$\\xi_-\\times 10^4$')\n", - "# plt.savefig('plots/xi_eb_minus_%s.pdf' %ver,bbox_inches='tight')\n", - "plt.show()\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Plot the $\\xi_{sys}$" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Read in the text file of the 2PCFs\n", - "\n", - "xisys_fname = f\"{cosmoval_data_dir}/leakage_{ver}/xi_sys.txt\"\n", - "print(f\"Reading xi_sys's from {xisys_fname}\")\n", - "\n", - "xisys = np.loadtxt(xisys_fname)\n", - "theta = xisys[:,0]\n", - "xip_sys = xisys[:,1]\n", - "xim_sys = xisys[:,2]\n", - "varxip_sys = xisys[:,3]\n", - "varxim_sys = xisys[:,4]\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "\n", - "# Plot the xi_+sys\n", - "ax1 = plt.subplot(111)\n", - "ax1.tick_params(axis='both', which='both', direction='in', length=6, width=1,\n", - " top=True, bottom=True, left=True, right=True)\n", - "ax1.yaxis.minorticks_on()\n", - "\n", - "ax1.errorbar(theta, xip_sys/xip, yerr=varxip_sys/xip, \n", - " fmt='o', markersize=4, capsize=2, capthick=1.5, ls = 'solid', lw=1.8,\n", - " label=r'$\\xi_{+,\\rm{sys}}$', \n", - " color='saddlebrown')\n", - "ax1.fill_between(theta, -varxip/xip,varxip/xip, color='palegreen', alpha=0.5)\n", - "ax1.axhline(0,ls='dashed',lw=1, color='grey')\n", - "ax1.text(0.07, 0.88, r'$\\xi_+$, 1-1', transform=ax1.transAxes,\n", - " bbox=dict(facecolor='white', edgecolor='black', boxstyle='round', pad=0.5))\n", - "ax1.set_xscale('log')\n", - "ax1.set_xlabel(r'$\\theta$ [arcmin]')\n", - "ax1.set_ylabel(r'$\\xi_{\\rm{sys}}/\\xi$')\n", - "# plt.savefig('plots/xip_sys_%s.pdf' %ver,bbox_inches='tight')\n", - "plt.show()\n", - "\n", - "# Plot the xi_- sys\n", - "ax2 = plt.subplot(111)\n", - "ax2.tick_params(axis='both', which='both', direction='in', length=6, width=1,\n", - " top=True, bottom=True, left=True, right=True)\n", - "ax2.yaxis.minorticks_on()\n", - "\n", - "ax2.errorbar(theta, xim_sys/xim, yerr=abs(varxim_sys/xim), \n", - " fmt='o', markersize=4, capsize=2, capthick=1.5, ls = 'solid', lw=1.8,\n", - " label=r'$\\xi_{-,\\rm{sys}}$', \n", - " color='teal')\n", - "ax2.fill_between(theta, -varxim/xim,varxim/xim, color='palegreen', alpha=0.5)\n", - "ax2.axhline(0,ls='dashed',lw=1, color='grey')\n", - "ax2.text(0.07, 0.88, r'$\\xi_-$, 1-1', transform=ax2.transAxes,\n", - " bbox=dict(facecolor='white', edgecolor='black', boxstyle='round', pad=0.5))\n", - "ax2.set_xscale('log')\n", - "ax2.set_xlabel(r'$\\theta$ [arcmin]')\n", - "ax2.set_ylabel(r'$\\xi_{\\rm{sys}}/\\xi$')\n", - "# plt.savefig('plots/xim_sys_%s.pdf' %ver,bbox_inches='tight')\n", - "plt.show()\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "sp-validation", - "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.9.21" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/cosmo_inference/notebooks/2D_cosmic_shear_paper_plots/matplotlib_config/paper.mplstyle b/cosmo_inference/notebooks/2D_cosmic_shear_paper_plots/matplotlib_config/paper.mplstyle deleted file mode 100644 index 11f59460..00000000 --- a/cosmo_inference/notebooks/2D_cosmic_shear_paper_plots/matplotlib_config/paper.mplstyle +++ /dev/null @@ -1,13 +0,0 @@ -figure.titlesize : 14 -figure.titleweight : bold -figure.autolayout : True -axes.titlesize : 14 -legend.fontsize : 8 -lines.linewidth : 1.5 -lines.markersize : 4 -axes.labelsize : 14 -xtick.labelsize : 12 -ytick.labelsize : 12 -text.usetex : True -font.family : serif -font.size : 12 \ No newline at end of file diff --git a/cosmo_inference/notebooks/2D_cosmic_shear_paper_plots/supporting_plots.ipynb b/cosmo_inference/notebooks/2D_cosmic_shear_paper_plots/supporting_plots.ipynb deleted file mode 100644 index 1de034f0..00000000 --- a/cosmo_inference/notebooks/2D_cosmic_shear_paper_plots/supporting_plots.ipynb +++ /dev/null @@ -1,155 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## SUPPORTING PLOTS\n", - "\n", - "This notebook plots all other supporting plots in the paper: the covariance matrix, and the redshift distributions." - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [], - "source": [ - "import matplotlib\n", - "from astropy.io import fits\n", - "import matplotlib.pyplot as plt\n", - "import uncertainties\n", - "import yaml\n", - "import os\n", - "import numpy as np\n", - "\n", - "plt.rcParams.update({'font.size': 25,'figure.figsize':[12,7]})\n", - "plt.rcParams.update({\"text.usetex\": True})\n", - "plt.rc('mathtext', fontset='stix')\n", - "plt.rc('font', family='serif')\n", - "\n", - "# Define path to data files (NOTE: YOU MUST HAVE RAN THE INFERENCE PIPELINE!)\n", - "data_dir = \"/n17data/mkilbing/astro/data/\"\n", - "ver = \"SP_v1.4.5_A\"\n", - "nz_file = data_dir + \"CFIS/v1.0/nz/blind_nz_cfis_shapepipe_2022v1.fits\"\n", - "covmat_file = f\"/n23data1/n06data/lgoh/scratch/UNIONS/cosmo_inference/data/{ver}/covs/cov_{ver}.txt\"\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Plot the redshift distribution $n(z)$" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "nz_hdu = fits.open(nz_file)\n", - "nz = nz_hdu[1].data\n", - "blind = 'A'\n", - "\n", - "z = nz_hdu[1].data['Z_%s'%blind]\n", - "bins=np.linspace(0,3,50)\n", - "\n", - "ax1 = plt.subplot(111)\n", - "ax1.tick_params(axis='both', which='both', direction='in', length=6, width=1,\n", - " top=True, bottom=True, left=True, right=True)\n", - "\n", - "y,edges = np.histogram(z, bins,density=True,weights=nz['som_w'])\n", - "centers = 0.5*(edges[1:]+ edges[:-1])\n", - "ax1.plot(centers,y,'-',lw = 2.5, alpha=0.7)\n", - "\n", - "ax1.set_xlabel(r'$z$')\n", - "ax1.set_ylabel(r'$n(z)$')\n", - "ax1.set_ylim([0,1.5])\n", - "# plt.savefig('plots/nz.pdf',bbox_inches='tight')\n", - "plt.show()\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Plot the covariance matrix" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": {}, - "outputs": [], - "source": [ - "cov = np.loadtxt(covmat_file)\n", - "ndata = len(cov[0])\n", - "cmap = 'seismic'" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "pp_norm = np.zeros((ndata,ndata))\n", - "for i in range(ndata):\n", - " for j in range(ndata):\n", - " pp_norm[i][j] = cov[i][j]/ np.sqrt(cov[i][i]*cov[j][j])\n", - "\n", - "fig = plt.figure()\n", - "ax = fig.add_subplot(1, 1, 1) \n", - "extent = (0, ndata, ndata, 0)\n", - "im3 = ax.imshow(pp_norm, cmap=cmap, vmin=-1, vmax=1, extent=extent)\n", - "\n", - "plt.axvline(x=int(ndata/2),color='black',linewidth=1.0)\n", - "plt.axhline(y=int(ndata/2),color='black',linewidth=1.0)\n", - "\n", - "fig.colorbar(im3, orientation='vertical')\n", - "ticks = np.arange(0,ndata+10,10)\n", - "tick_labels = np.array([0,10,0,10,20])\n", - "ax.set_xticks(ticks,labels= tick_labels)\n", - "ax.set_yticks(ticks,labels= tick_labels)\n", - "\n", - "\n", - "ax.text(int(ndata/4), ndata+5, r'$\\xi_+(\\theta)$')\n", - "ax.text(3*int(ndata/4), ndata+5, r'$\\xi_-(\\theta)$')\n", - "ax.text(-9, int(ndata/4), r'$\\xi_+(\\theta)$')\n", - "ax.text(-9, 3*int(ndata/4), r'$\\xi_-(\\theta)$')\n", - "\n", - "# plt.savefig(\"plots/covmat.pdf\", bbox_inches='tight')\n", - "plt.show()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "sp-validation", - "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.9.21" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/cosmo_inference/notebooks/2D_cosmic_shear_paper_plots/workflow/Snakefile b/cosmo_inference/notebooks/2D_cosmic_shear_paper_plots/workflow/Snakefile deleted file mode 100644 index 4ca68601..00000000 --- a/cosmo_inference/notebooks/2D_cosmic_shear_paper_plots/workflow/Snakefile +++ /dev/null @@ -1,45 +0,0 @@ -import os -from pathlib import Path - -configfile: "config/config.yaml" - - -rule plot_xi_bestfit: - """Plot ξ± data with best-fit theory from fiducial chain.""" - input: - xi_data=config["xi_data"], - pure_eb_data=config["pure_eb_data"], - output: - f"/n17data/cdaley/unions/pure_eb/results/paper_plots/{config['version']}_xi_with_bestfit.pdf", - params: - bestfit_dir=config["bestfit_dir"], - script: - "scripts/plot_xi_bestfit.py" - - -# --- Legacy rules (commented out, require old config keys) --- -# def find_cosmosis_inputs(): -# chain = config["chain"] -# for ini_dir in config["ini_dirs"]: -# ini_file = Path(ini_dir) / f"cosmosis_pipeline_{chain}.ini" -# if os.path.exists(ini_file): -# return ini_file -# raise FileNotFoundError( -# f"Cosmosis input file not found for chain {chain} in specified directories." -# ) -# -# rule get_bestfit_model: -# input: -# inference_ini=find_cosmosis_inputs(), -# output: -# bestfit_values_ini=f"results/{config['chain']}/bestfit_values.ini", -# cosmosis_ini=f"results/{config['chain']}/cosmosis.ini", -# xi_shear=f"results/{config['chain']}/bestfit_xi_shear.txt", -# xi_sys=f"results/{config['chain']}/bestfit_xi_sys.txt", -# params: -# bestfit_dir=f"results/{config['chain']}", -# script: -# "scripts/get_bestfit_model.py" -# -# rule paper_plots: -# ... # References min_sep, max_sep, nbins, etc. from old config diff --git a/cosmo_inference/notebooks/2D_cosmic_shear_paper_plots/workflow/scripts/contour_plots.py b/cosmo_inference/notebooks/2D_cosmic_shear_paper_plots/workflow/scripts/contour_plots.py deleted file mode 100644 index 7706d392..00000000 --- a/cosmo_inference/notebooks/2D_cosmic_shear_paper_plots/workflow/scripts/contour_plots.py +++ /dev/null @@ -1,183 +0,0 @@ -""" -Get the best-fit (really weighted posterior mean) parameters from the MCMC -chain and run cosmosis to get the best-fit theory curve for plotting elsewhere. -""" - -# %% -import configparser -import os -import subprocess as sp -import sys - -import getdist as gd -import numpy as np -from astropy.io import fits -from scipy.interpolate import interp1d - -if hasattr(sys, "ps1"): - from snakemake_helpers import get_pipe - - snakemake = get_pipe( - "contour_plots", - "/n17data/cdaley/unions/sp_validation/cosmo_inference/notebooks/2D_cosmic_shear_paper_plots", - ) -else: - from snakemake.script import snakemake - -params = snakemake.params - -# %% change a few values in the inference config and save it to a new file -inference_config = configparser.ConfigParser() -inference_config.optionxform = str -inference_config.read(snakemake.input.inference_ini) - -inference_config["runtime"]["sampler"] = "test" -inference_config["pipeline"]["values"] = snakemake.output.bestfit_values_ini - -prior_path = inference_config["pipeline"]["priors"] -if prior_path.startswith("cosmosis_config"): # sacha - base_dir = snakemake.input.inference_ini.split("cosmosis_config")[0] - inference_config["pipeline"]["priors"] = base_dir + prior_path - inference_config["DEFAULT"]["FITS_FILE"] = ( - base_dir + inference_config["DEFAULT"]["FITS_FILE"] - ) -if "cosmosis_config/priors_" in prior_path and "lgoh" in prior_path: # lisa - inference_config["pipeline"]["priors"] = prior_path.replace( - "priors_", "priors/priors_" - ) - -inference_config["test"]["save_dir"] = snakemake.params["bestfit_dir"] - -with open(snakemake.output.cosmosis_ini, "w", encoding="utf-8") as f: - inference_config.write(f) - - -# %% -# % Get best-fit (really posterior mean) parameters from MCMC chain -chain = gd.mcsamples.loadMCSamples( - inference_config["output"]["filename"] - .split(".txt")[0] - .replace("samples_", "getdist_") -) -likestats = chain.getLikeStats() -bestfit_idx = np.argmax(chain.loglikes) -maxlike = chain.loglikes[bestfit_idx] -print(f"Maximum Likelihood: {maxlike:.5g}") -best_fit = { - par.name: np.average(chain.samples[:, i], weights=chain.weights) - for i, par in enumerate(likestats.names) -} -# %% create cosmosis bestfit values ini file - -section_map = { - "omch2": "cosmological_parameters", - "ombh2": "cosmological_parameters", - "h0": "cosmological_parameters", - "n_s": "cosmological_parameters", - "s_8_input": "cosmological_parameters", - "logt_agn": "halo_model_parameters", - "a": "intrinsic_alignment_parameters", - "m1": "shear_calibration_parameters", - "bias_1": "nofz_shifts", - "alpha": "psf_leakage_parameters", - "beta": "psf_leakage_parameters", -} - -content = """ -[cosmological_parameters] - -tau = 0.0544 -w = -1.0 -massive_nu = 1 -massless_nu = 2.046 -omega_k = 0.0 -wa = 0.0 - -[halo_model_parameters] - -[intrinsic_alignment_parameters] - -[shear_calibration_parameters] - -[nofz_shifts] - -[psf_leakage_parameters] -""" - -with open(snakemake.output.bestfit_values_ini, "w", encoding="utf-8") as f: - f.write(content) - f.close() - -best_fit_config = configparser.ConfigParser() -best_fit_config.optionxform = str -best_fit_config.read(snakemake.output.bestfit_values_ini) - -for param, value in best_fit.items(): - section = section_map.get(param) - if section is None: - continue - if section not in best_fit_config: - best_fit_config.add_section(section) - best_fit_config[section][param] = str(value) -with open(snakemake.output.bestfit_values_ini, "w", encoding="utf-8") as f: - best_fit_config.write(f) - - -# %% - -env = os.environ.copy() -env["LD_LIBRARY_PATH"] = ( - "/home/guerrini/.conda/envs/sp_validation/lib/python3.9/site-packages/cosmosis/datablock:" - + env.get("LD_LIBRARY_PATH", "") -) - -# Run cosmosis -result = sp.run( - ["cosmosis", snakemake.output.cosmosis_ini], - env=env, - capture_output=True, - text=True, - check=True, -) -print(f"STDOUT:\n{result.stdout}") -print(f"STDERR:\n{result.stderr}") -# %% -theta_model = ( - np.rad2deg(np.loadtxt(snakemake.params["bestfit_dir"] + "/shear_xi_plus/theta.txt")) - * 60 -) -theta_data = fits.open(inference_config["DEFAULT"]["FITS_FILE"])["XI_PLUS"].data["ANG"] -theta_out = np.geomspace(0.01, 300, 1000) - -xi_plus, xi_minus = [ - interp1d( - theta_model, - np.loadtxt(snakemake.params["bestfit_dir"] + f"/shear_{var}/bin_1_1.txt"), - kind="cubic", - fill_value="extrapolate", - )(theta_out) - for var in ["xi_plus", "xi_minus"] -] -xi_sys_plus, xi_sys_minus = [ - interp1d( - theta_data, - np.loadtxt(snakemake.params["bestfit_dir"] + f"/xi_sys/shear_{var}.txt"), - kind="cubic", - fill_value="extrapolate", - )(theta_out) - for var in ["xi_plus", "xi_minus"] -] -# %% -np.savetxt( - snakemake.output.xi_shear, - np.column_stack([theta_out, xi_plus, xi_minus]), - header="theta xi_plus xi_minus", - fmt="%g", -) -np.savetxt( - snakemake.output.xi_sys, - np.column_stack([theta_out, xi_sys_plus, xi_sys_minus]), - header="theta xi_sys_plus xi_sys_minus", - fmt="%g", -) -# %% diff --git a/cosmo_inference/notebooks/2D_cosmic_shear_paper_plots/workflow/scripts/eb_plots.py b/cosmo_inference/notebooks/2D_cosmic_shear_paper_plots/workflow/scripts/eb_plots.py deleted file mode 100644 index 5d7b7404..00000000 --- a/cosmo_inference/notebooks/2D_cosmic_shear_paper_plots/workflow/scripts/eb_plots.py +++ /dev/null @@ -1,389 +0,0 @@ -""" -Plot Data 2PCF as well as best-fit model, B-modes, and leakage systematics. -""" - -# %% -# if interactive -import os -import sys - -import matplotlib.pyplot as plt -import numpy as np -import seaborn as sns -from IPython import get_ipython -from mpl_toolkits.axes_grid1 import make_axes_locatable -from scipy import stats - -ipython = get_ipython() - -# enable autoreload for interactive sessions -if ipython is not None: - ipython.run_line_magic("load_ext", "autoreload") - ipython.run_line_magic("autoreload", "2") -else: - # Force unbuffered stdout and stderr - sys.stdout = os.fdopen(sys.stdout.fileno(), "w", buffering=1) # line-buffered - sys.stderr = os.fdopen(sys.stderr.fileno(), "w", buffering=1) - -from sp_validation.cosmo_val import CosmologyValidation - -if ipython is not None: - ipython.run_line_magic("matplotlib", "inline") - os.chdir( - "/n17data/cdaley/unions/sp_validation/cosmo_inference/notebooks/2D_cosmic_shear_paper_plots/workflow/scripts" - ) - from snakemake_helpers import get_pipe - - snakemake = get_pipe("eb_plots", workdir="../") -else: - from snakemake.script import snakemake - -params = snakemake.params -config = snakemake.config -plt.style.use(config["plot_style"]) - -# %% -cwd = os.getcwd() -os.chdir("/n17data/cdaley/unions/sp_validation/notebooks/cosmo_val") - -cv = CosmologyValidation( - versions=[config["version"]], -) -# %% -eb_results = cv.calculate_pure_eb(version=config["version"], **config["pure_eb"]) -# %% -cosebis_results = cv.calculate_cosebis(version=config["version"], **config["cosebis"]) -cosebis_results_fiducial = cosebis_results[tuple(config["fiducial_scale_cut"])] - -# %% -os.chdir(cwd) - -# %% -theta_model, xi_plus_theory, xi_minus_theory = np.loadtxt( - snakemake.input.bestfit_xi_shear, unpack=True -) - -theta_model, xi_plus_sys, xi_minus_sys = np.loadtxt( - snakemake.input.bestfit_xi_sys, unpack=True -) - - -# %% -def populate_eb_results(results, start_p, start_m, stop=None): - results["start_p"] = start_p - results["start_m"] = start_m - stop = stop if stop is not None else results["gg"].nbins - 1 - results["stop"] = stop - - nbins, npatch = results["gg"].nbins, results["gg"].npatch1 - hartlap_factor = (npatch - nbins - 2) / (npatch - 1) - - starts = { - key: start_p if "xip" in key else start_m - for key in ["xip_E", "xim_E", "xip_B", "xim_B", "xip_amb", "xim_amb"] - } - nbins_eff = {key: stop - starts[key] for key in starts} - - # Compute and store covariance blocks and stds in results with explicit names - for i, key in enumerate(["xip_E", "xim_E", "xip_B", "xim_B", "xip_amb", "xim_amb"]): - cov_block = results["cov"][ - nbins * i : nbins * (i + 1), nbins * i : nbins * (i + 1) - ] - std_block = np.sqrt(np.diag(cov_block)) - results[f"cov_{key}"] = cov_block - results[f"std_{key}"] = std_block - - chi2s = { - key: results[key][starts[key] : stop] - @ ( - hartlap_factor - * np.linalg.inv( - results[f"cov_{key}"][starts[key] : stop, starts[key] : stop] - ) - ) - @ results[key][starts[key] : stop] - for key in ["xip_E", "xim_E", "xip_B", "xim_B"] - } - # Store chi2s in results - for key in chi2s: - results[f"{key}_chi2"] = chi2s[key] - - xip_B_pte, xim_B_pte = [ - stats.chi2.sf(chi2s[key], nbins_eff[key]) for key in ["xip_B", "xim_B"] - ] - # Store PTEs in results - results["xip_B_pte"] = xip_B_pte - results["xim_B_pte"] = xim_B_pte - - stop = results["stop"] - for pm in "pm": - results[f"xi{pm}_B_ptes"] = [] - for start in range(stop): - nbins_eff = stop - start - - chi2s = { - key: results[key][start:stop] - @ ( - hartlap_factor - * np.linalg.inv(results[f"cov_{key}"][start:stop, start:stop]) - ) - @ results[key][start:stop] - for key in [f"xi{pm}_E", f"xi{pm}_B"] - } - - results[f"xi{pm}_B_ptes"].append( - stats.chi2.sf(chi2s[f"xi{pm}_B"], nbins_eff) - ) - return results - - -populate_eb_results(eb_results, 10, 15, eb_results["gg"].nbins - 2) - -# %% -# Plot Pure 2PCFs -gg, gg_int = eb_results["gg"], eb_results["gg_int"] -fig, axs = plt.subplots(nrows=1, ncols=2, figsize=(8, 4)) - -axs[0].plot( - theta_model, - theta_model * (xi_plus_theory + xi_plus_sys) / 1e-4, - color="black", - # ms=12, - label=r"Best-fit $\xi_{+}^{\rm th} + \xi_{+}^{\rm sys}$", -) - -axs[0].plot( - theta_model, - theta_model * (xi_plus_theory) / 1e-4, - color="darkmagenta", - ls="--", - # ms=12, - label=r"Best-fit $\xi_{+}^{\rm th}$", -) - -axs[0].plot( - theta_model, - theta_model * xi_plus_sys / 1e-4, - color="dodgerblue", - # ms=12, - label=r"Best-fit $\xi_{+}^{\rm sys}$", -) - -axs[0].errorbar( - gg.meanr, - gg.meanr * gg.xip / 1e-4, - yerr=gg.meanr * np.sqrt(gg.varxip) / 1e-4, - fmt="k.", - # ms=12, - # label=r"$\xi_{+}=\xi_{+}^{E}+\xi_{+}^{B}+\xi_{+}^{\mathrm{amb}}$", - label=r"$\xi_{+}$", -) - -axs[0].errorbar( - gg.meanr, - gg.meanr * eb_results["xip_B"] / 1e-4, - yerr=gg.meanr * eb_results["std_xip_B"] / 1e-4, - color="crimson", - ls="", - marker=".", - # ms=12, - label=rf"$\xi_{{+}}^{{B}}, {{\rm PTE}}={np.round(eb_results['xip_B_pte'],4)}$", -) - - -axs[0].axvspan(0, gg.left_edges[eb_results["start_p"]], color="gray", alpha=0.1) -axs[0].axvspan(gg.right_edges[eb_results["stop"]], 1000, color="gray", alpha=0.1) -axs[0].axhline(0, ls="--", color="k", alpha=0.5) -axs[0].set_xscale("log") -axs[0].set_xticks([0.1, 1, 10, 100], [r"$0.1$", r"$1$", r"$10$", r"$100$"]) -axs[0].set_xlabel(r"$\theta$ (arcmin)") -axs[0].set_ylabel(r"$\theta\xi\times10^{4}$") -axs[0].legend(loc="upper left") -axs[0].set_ylim(-0.45, 1.9) -axs[0].set_xlim(1, 170) -axs[0].set_title(r"$\xi_{+}$") - -axs[1].plot( - theta_model, - theta_model * (xi_minus_theory + xi_minus_sys) / 1e-4, - color="black", - # ms=12, - label=r"Best-fit $\xi_{-}^{\rm th} + \xi_{-}^{\rm sys}$", -) - -axs[1].plot( - theta_model, - theta_model * (xi_minus_theory) / 1e-4, - color="darkmagenta", - ls="--", - # ms=12, - label=r"Best-fit $\xi_{-}^{\rm th}$", -) - -axs[1].plot( - theta_model, - theta_model * xi_minus_sys / 1e-4, - color="dodgerblue", - # ms=12, - label=r"Best-fit $\xi_{-}^{\rm sys}$", -) - -axs[1].errorbar( - gg.meanr, - gg.meanr * gg.xim / 1e-4, - yerr=gg.meanr * np.sqrt(gg.varxim) / 1e-4, - fmt="k.", - # ms=12, - # label=r"$\xi_{-}=\xi_{-}^{E}-\xi_{-}^{B}+\xi_{-}^{\mathrm{amb}}$", - label=r"$\xi_{-}$", -) - -axs[1].errorbar( - gg.meanr, - gg.meanr * eb_results["xim_B"] / 1e-4, - yerr=gg.meanr * eb_results["std_xim_B"] / 1e-4, - color="crimson", - ls="", - marker=".", - # ms=12, - # label=r"$\xi_{-}^{B}$", - label=rf"$\xi_{{-}}^{{B}}, {{\rm PTE}}={np.round(eb_results['xim_B_pte'],4)}$", -) - -axs[1].axvspan(0, gg.left_edges[eb_results["start_m"]], color="gray", alpha=0.1) -axs[1].axvspan(gg.right_edges[eb_results["stop"]], 1000, color="gray", alpha=0.1) -axs[1].axhline(0, ls="--", color="k", alpha=0.5) -axs[1].set_xscale("log") -axs[1].set_xlabel(r"$\theta$ (arcmin)") -axs[1].legend(loc="upper left") -axs[1].set_ylim(-0.45, 1.9) -axs[1].set_title(r"$\xi_{-}$") -axs[1].set_xticks([0.1, 1, 10, 100], [r"$0.1$", r"$1$", r"$10$", r"$100$"]) -axs[1].set_xlim(1, 170) - -plt.savefig(snakemake.output["xis"], bbox_inches="tight", dpi=300) - - -# %% -# Plot 2PCF covariance -def correlation_from_covariance(covariance): - v = np.sqrt(np.diag(covariance)) - outer_v = np.outer(v, v) - correlation = covariance / outer_v - correlation[covariance == 0] = 0 - return correlation - - -fig, ax = plt.subplots(figsize=(4, 4)) -im = ax.matshow(correlation_from_covariance(eb_results["cov"]), cmap="vlag") - -for ticks in (plt.xticks, plt.yticks): - ticks( - range(10, 111, 20), - [ - r"$\xi_+^{E}$", - r"$\xi_-^{E}$", - r"$\xi_+^{B}$", - r"$\xi_-^{B}$", - r"$\xi_+^{\rm amb}$", - r"$\xi_-^{\rm amb}$", - ], - ) - ticks(range(0, 121, 20), minor=True) -ax.tick_params(axis="both", which="major", length=0) - -im.set_clim(-1, 1) -divider = make_axes_locatable(ax) -cax = divider.append_axes("right", size="5%", pad=0.1) # Adjust size/pad as needed -plt.colorbar(im, cax=cax) -# ax.set_title("Pure E/B Sampled Correlation Matrix") -plt.savefig(snakemake.output["xis_corr"], dpi=300, bbox_inches="tight") - -# %% -# Plot COSEBIS -plt.figure(figsize=(4, 4)) -plt.errorbar( - cosebis_results_fiducial["modes"], - cosebis_results_fiducial["E"] * 1e11, - yerr=np.sqrt(np.diag(cosebis_results_fiducial["cov_E"])) * 1e11, - label=rf"COSEBIs E-modes; $\sqrt{{\chi_0^2}}$ = {cosebis_results_fiducial['E_snr']:.2f}", -) -plt.errorbar( - cosebis_results_fiducial["modes"], - cosebis_results_fiducial["B"] * 1e11, - yerr=np.sqrt(np.diag(cosebis_results_fiducial["cov_B"])) * 1e11, - c="crimson", - label=rf"COSEBIs B-modes; PTE $B_0$ = {cosebis_results_fiducial['B0_pte']:.2f}, $B_{{\rm all}}$ = {cosebis_results_fiducial['B_pte']:.2f}", -) - -plt.axhline(0, ls="--", color="k") -plt.legend() -plt.xlabel(r"$n$ (mode)") -plt.ylabel(r"$E_n,B_n \times 10^{11}$") -plt.savefig(snakemake.output["cosebis"], dpi=300, bbox_inches="tight") - -# %% -# Plot COSEBIS covariance - -fig, ax = plt.subplots(figsize=(4, 4)) -im = ax.imshow(cosebis_results_fiducial["cov_EB"], cmap="coolwarm") - -nmodes = len(cosebis_results_fiducial["E"]) -for ticks in (plt.xticks, plt.yticks): - ticks( - np.arange(nmodes / 2, nmodes * 2, nmodes), - [r"$E_n$", r"$B_n$"], - ) - ticks([nmodes], minor=True) - -clim = np.max(np.abs(cosebis_results_fiducial["cov_EB"])) -im.set_clim(-clim, clim) -divider = make_axes_locatable(ax) -cax = divider.append_axes("right", size="5%", pad=0.1) -plt.colorbar(im, cax=cax) -plt.savefig(snakemake.output["cosebis_cov"], dpi=300, bbox_inches="tight") - -# %% -plt.figure(figsize=(4, 4)) -plt.plot( - gg.meanr[0 : eb_results["stop"]], - eb_results["xip_B_ptes"], - label=r"$\xi_{B+}$", - marker="$+$", - c="dodgerblue", - ms=8, - ls="", -) -plt.plot( - gg.meanr[0 : eb_results["stop"]], - eb_results["xim_B_ptes"], - c="crimson", - label=r"$\xi_{B-}$", - marker="$-$", - ms=8, - ls="", -) - -B_ptes = [cosebis_results[scale_cut]["B_pte"] for scale_cut in cosebis_results] - -plt.plot( - [scale_cut[0] for scale_cut in cosebis_results], - B_ptes, - c="k", - label=r"$B_{n}$", - marker=".", - ms=8, - ls="", -) - -plt.axhspan(0, 0.05, ls="--", color="k", alpha=0.5) -plt.axhspan(0.95, 1, ls="--", color="k", alpha=0.5) - -plt.xscale("log") -# plt.yscale("log") -plt.ylim(0, 1) -plt.xlabel(r"$\theta$ (arcmin)") -plt.ylabel(r"PTE") -plt.legend() -# plt.title("B-mode PTEs as a function of lower scale cut") -plt.savefig(snakemake.output["ptes"], dpi=300, bbox_inches="tight") diff --git a/cosmo_inference/notebooks/2D_cosmic_shear_paper_plots/workflow/scripts/get_bestfit_model.py b/cosmo_inference/notebooks/2D_cosmic_shear_paper_plots/workflow/scripts/get_bestfit_model.py deleted file mode 100644 index 0f269207..00000000 --- a/cosmo_inference/notebooks/2D_cosmic_shear_paper_plots/workflow/scripts/get_bestfit_model.py +++ /dev/null @@ -1,175 +0,0 @@ -""" -Get the best-fit (really weighted posterior mean) parameters from the MCMC -chain and run cosmosis to get the best-fit theory curve for plotting elsewhere. -""" - -# %% -import configparser -import os -import subprocess as sp -import sys - -import getdist as gd -import numpy as np -from astropy.io import fits -from scipy.interpolate import interp1d - -if hasattr(sys, "ps1"): - from snakemake_helpers import get_pipe - - snakemake = get_pipe( - "results/SP_v1.4.5_A_sc_10_60/bestfit_theory.txt", - "/n17data/cdaley/unions/sp_validation/cosmo_inference/notebooks/2D_cosmic_shear_paper_plots", - ) -else: - from snakemake.script import snakemake - -params = snakemake.params - -# %% change a few values in the inference config and save it to a new file -inference_config = configparser.ConfigParser() -inference_config.optionxform = str -inference_config.read(snakemake.input.inference_ini) - -inference_config["runtime"]["sampler"] = "test" -inference_config["pipeline"]["values"] = snakemake.output.bestfit_values_ini - -prior_path = inference_config["pipeline"]["priors"] -if prior_path.startswith("cosmosis_config"): # sacha - base_dir = snakemake.input.inference_ini.split("cosmosis_config")[0] - inference_config["pipeline"]["priors"] = base_dir + prior_path - inference_config["DEFAULT"]["FITS_FILE"] = base_dir + inference_config["DEFAULT"]["FITS_FILE"] -if "cosmosis_config/priors_" in prior_path and "lgoh" in prior_path: # lisa - inference_config["pipeline"]["priors"] = prior_path.replace( - "priors_", "priors/priors_") - -inference_config["test"]["save_dir"] = snakemake.params["bestfit_dir"] - -with open(snakemake.output.cosmosis_ini, "w", encoding="utf-8") as f: - inference_config.write(f) - - -# %% -# % Get best-fit (really posterior mean) parameters from MCMC chain -chain = gd.mcsamples.loadMCSamples( - inference_config["output"]["filename"].split(".txt")[0] - .replace("samples_", "getdist_") -) -likestats = chain.getLikeStats() -bestfit_idx = np.argmax(chain.loglikes) -maxlike = chain.loglikes[bestfit_idx] -print(f"Maximum Likelihood: {maxlike:.5g}") -best_fit = { - par.name: np.average(chain.samples[:, i], weights=chain.weights) - for i, par in enumerate(likestats.names) -} -# %% create cosmosis bestfit values ini file - -section_map = { - "omch2": "cosmological_parameters", - "ombh2": "cosmological_parameters", - "h0": "cosmological_parameters", - "n_s": "cosmological_parameters", - "s_8_input": "cosmological_parameters", - "logt_agn": "halo_model_parameters", - "a": "intrinsic_alignment_parameters", - "m1": "shear_calibration_parameters", - "bias_1": "nofz_shifts", - "alpha": "psf_leakage_parameters", - "beta": "psf_leakage_parameters", -} - -content = """ -[cosmological_parameters] - -tau = 0.0544 -w = -1.0 -massive_nu = 1 -massless_nu = 2.046 -omega_k = 0.0 -wa = 0.0 - -[halo_model_parameters] - -[intrinsic_alignment_parameters] - -[shear_calibration_parameters] - -[nofz_shifts] - -[psf_leakage_parameters] -""" - -with open(snakemake.output.bestfit_values_ini, "w", encoding="utf-8") as f: - f.write(content) - f.close() - -best_fit_config = configparser.ConfigParser() -best_fit_config.optionxform = str -best_fit_config.read(snakemake.output.bestfit_values_ini) - -for param, value in best_fit.items(): - section = section_map.get(param) - if section is None: - continue - if section not in best_fit_config: - best_fit_config.add_section(section) - best_fit_config[section][param] = str(value) -with open(snakemake.output.bestfit_values_ini, "w", encoding="utf-8") as f: - best_fit_config.write(f) - - -# %% - -env = os.environ.copy() -env["LD_LIBRARY_PATH"] = ( - "/home/guerrini/.conda/envs/sp_validation/lib/python3.9/site-packages/cosmosis/datablock:" - + env.get("LD_LIBRARY_PATH", "") -) - -# Run cosmosis -result = sp.run( - ["cosmosis", snakemake.output.cosmosis_ini], env=env, capture_output=True, text=True, check=True -) -print(f"STDOUT:\n{result.stdout}") -print(f"STDERR:\n{result.stderr}") -# %% -theta_model = ( - np.rad2deg(np.loadtxt(snakemake.params["bestfit_dir"] + "/shear_xi_plus/theta.txt")) - * 60 -) -theta_data = fits.open(inference_config["DEFAULT"]["FITS_FILE"])["XI_PLUS"].data["ANG"] -theta_out = np.geomspace(0.01, 300, 1000) - -xi_plus, xi_minus = [ - interp1d( - theta_model, - np.loadtxt(snakemake.params["bestfit_dir"] + f"/shear_{var}/bin_1_1.txt"), - kind="cubic", - fill_value="extrapolate", - )(theta_out) - for var in ["xi_plus", "xi_minus"] -] -xi_sys_plus, xi_sys_minus = [ - interp1d( - theta_data, - np.loadtxt(snakemake.params["bestfit_dir"] + f"/xi_sys/shear_{var}.txt"), - kind="cubic", - fill_value="extrapolate", - )(theta_out) - for var in ["xi_plus", "xi_minus"] -] -# %% -np.savetxt( - snakemake.output.xi_shear, - np.column_stack([theta_out, xi_plus, xi_minus]), - header="theta xi_plus xi_minus", - fmt="%g", -) -np.savetxt( - snakemake.output.xi_sys, - np.column_stack([theta_out, xi_sys_plus, xi_sys_minus]), - header="theta xi_sys_plus xi_sys_minus", - fmt="%g", -) -# %% diff --git a/cosmo_inference/notebooks/2D_cosmic_shear_paper_plots/workflow/scripts/plot_xi_bestfit.py b/cosmo_inference/notebooks/2D_cosmic_shear_paper_plots/workflow/scripts/plot_xi_bestfit.py deleted file mode 100644 index 48b7ae60..00000000 --- a/cosmo_inference/notebooks/2D_cosmic_shear_paper_plots/workflow/scripts/plot_xi_bestfit.py +++ /dev/null @@ -1,185 +0,0 @@ -""" -Plot ξ± data with best-fit theory curve from fiducial cosmology inference. - -Style matches the original paper_plots.py figure: -- Black line: Best-fit ξ_th + ξ_sys -- Blue line: Best-fit ξ_sys alone -- Black points: Data ξ± -- Red points: B-mode ξ_B -- Gray shaded region: excluded by fiducial scale cuts -""" - -import matplotlib.pyplot as plt -import numpy as np -from scipy.interpolate import interp1d - -from snakemake.script import snakemake - -# Load plot style -plt.style.use(snakemake.config["plot_style"]) - -# Fiducial scale cuts from Paper IV (main.tex Sect. 5.5) -# Based on B-modes, PSF leakage, and nonlinear modelling -# [12, 83] for both xi+/xi- with v1.4.6.3 fiducial -scale_cut_xip = [12, 83] # arcmin -scale_cut_xim = [12, 83] # arcmin - -# --- Load data ξ± --- -data = np.loadtxt(snakemake.input.xi_data, comments="#") -theta_data = data[:, 1] # meanr in arcmin -xip_data = data[:, 3] -xim_data = data[:, 4] -sigma_xip = data[:, 7] -sigma_xim = data[:, 8] - -# --- Load B-mode data --- -eb_data = np.load(snakemake.input.pure_eb_data) -theta_eb = eb_data["theta"] -xip_B = eb_data["xip_B"] -xim_B = eb_data["xim_B"] -cov_pure_eb = eb_data["cov_pure_eb"] - -# Extract B-mode uncertainties from covariance (blocks 2 and 3) -nbins = len(theta_eb) -sigma_xip_B = np.sqrt(np.diag(cov_pure_eb[2*nbins:3*nbins, 2*nbins:3*nbins])) -sigma_xim_B = np.sqrt(np.diag(cov_pure_eb[3*nbins:4*nbins, 3*nbins:4*nbins])) - -# TreeCorr bin edges: log-spaced from min_sep to max_sep -# These are the actual bin boundaries, not derived from meanr -min_sep, max_sep = 1.0, 250.0 -bin_edges = np.geomspace(min_sep, max_sep, nbins + 1) - -# Nominal bin centers (geometric mean of edges) for matching scale cuts -bin_centers_nominal = np.sqrt(bin_edges[:-1] * bin_edges[1:]) - -# Compute actual bin edge boundaries for scale cuts -def get_bin_edge_cuts(centers, edges, scale_cut): - """Get bin edges that bound the included bins based on nominal centers.""" - mask = (centers >= scale_cut[0]) & (centers <= scale_cut[1]) - idx_first = np.where(mask)[0][0] - idx_last = np.where(mask)[0][-1] - return edges[idx_first], edges[idx_last + 1] - -edge_cut_xip = get_bin_edge_cuts(bin_centers_nominal, bin_edges, scale_cut_xip) -edge_cut_xim = get_bin_edge_cuts(bin_centers_nominal, bin_edges, scale_cut_xim) - -# --- Load best-fit theory --- -bestfit_dir = snakemake.params.bestfit_dir - -# Theory theta in radians, convert to arcmin -theta_theory_rad = np.loadtxt(f"{bestfit_dir}/shear_xi_plus/theta.txt", comments="#") -theta_theory = np.rad2deg(theta_theory_rad) * 60 # radians -> arcmin - -xip_theory = np.loadtxt(f"{bestfit_dir}/shear_xi_plus/bin_1_1.txt", comments="#") -xim_theory = np.loadtxt(f"{bestfit_dir}/shear_xi_minus/bin_1_1.txt", comments="#") - -# Load xi_sys (PSF leakage contribution) -theta_sys_rad = np.loadtxt(f"{bestfit_dir}/xi_sys/theta.txt", comments="#") -theta_sys = np.rad2deg(theta_sys_rad) * 60 -xip_sys = np.loadtxt(f"{bestfit_dir}/xi_sys/shear_xi_plus.txt", comments="#") -xim_sys = np.loadtxt(f"{bestfit_dir}/xi_sys/shear_xi_minus.txt", comments="#") - -# Interpolate to common fine grid -theta_fine = np.geomspace(0.5, 300, 500) -xip_th_interp = interp1d(theta_theory, xip_theory, kind="cubic", fill_value="extrapolate")(theta_fine) -xim_th_interp = interp1d(theta_theory, xim_theory, kind="cubic", fill_value="extrapolate")(theta_fine) -xip_sys_interp = interp1d(theta_sys, xip_sys, kind="cubic", fill_value="extrapolate")(theta_fine) -xim_sys_interp = interp1d(theta_sys, xim_sys, kind="cubic", fill_value="extrapolate")(theta_fine) - -# --- Plotting parameters --- -scale_factor = 1e-4 -xlim = [1, 250] -ylim = [-0.15, 1.25] - -# Smaller markers -ms_data = 3 -ms_bmode = 3 -capsize = 1.5 -elinewidth = 0.8 - -# --- Create figure --- -fig, axes = plt.subplots(1, 2, figsize=(10, 4.5), sharey=True) - -plot_configs = [ - (axes[0], xip_data, sigma_xip, xip_B, sigma_xip_B, xip_th_interp, xip_sys_interp, - edge_cut_xip, r"$\xi_+$", "+"), - (axes[1], xim_data, sigma_xim, xim_B, sigma_xim_B, xim_th_interp, xim_sys_interp, - edge_cut_xim, r"$\xi_-$", "-"), -] - -for idx, (ax, xi_data_arr, sigma_xi, xi_B, sigma_B, xi_th, xi_sys, edge_cut, label, pm) in enumerate(plot_configs): - - show_legend = (idx == 1) # Only right panel - - # Gray out excluded regions (outside fiducial scale cuts, using bin edges) - ax.axvspan(xlim[0], edge_cut[0], color="0.90", zorder=0, alpha=0.7) - ax.axvspan(edge_cut[1], xlim[1], color="0.90", zorder=0, alpha=0.7) - - # Best-fit theory + systematics (black line) - ax.plot( - theta_fine, - theta_fine * (xi_th + xi_sys) / scale_factor, - "-", - color="k", - lw=1.5, - label=r"Best-fit $\xi^{\mathrm{th}}_\pm + \xi^{\mathrm{sys}}_\pm$" if show_legend else None, - zorder=2, - ) - - # Best-fit systematics alone (blue line) - ax.plot( - theta_fine, - theta_fine * xi_sys / scale_factor, - "-", - color="C0", - lw=1.2, - label=r"Best-fit $\xi^{\mathrm{sys}}_\pm$" if show_legend else None, - zorder=2, - ) - - # Data ξ± (black points) - plot at meanr - ax.errorbar( - theta_data, - theta_data * xi_data_arr / scale_factor, - yerr=theta_data * sigma_xi / scale_factor, - fmt="o", - color="k", - markersize=ms_data, - capsize=capsize, - elinewidth=elinewidth, - label=r"$\xi_\pm$" if show_legend else None, - zorder=3, - ) - - # B-mode (red points) - slight x-offset for visibility - theta_eb_offset = theta_eb * 1.03 # 3% offset to right - ax.errorbar( - theta_eb_offset, - theta_eb_offset * xi_B / scale_factor, - yerr=theta_eb_offset * sigma_B / scale_factor, - fmt="o", - color="C3", - markersize=ms_bmode, - capsize=capsize, - elinewidth=elinewidth, - alpha=0.85, - label=r"$\xi^B_\pm$" if show_legend else None, - zorder=3, - ) - - # Zero line - ax.axhline(0, color="gray", linestyle="--", alpha=0.8, linewidth=0.8, zorder=1) - - ax.set_xscale("log") - ax.set_xlim(xlim) - ax.set_ylim(ylim) - ax.set_xlabel(r"$\theta$ (arcmin)") - ax.set_title(label) - if show_legend: - ax.legend(loc="upper left") - -axes[0].set_ylabel(r"$\theta\xi \times 10^4$") - -fig.tight_layout() -fig.savefig(snakemake.output[0], dpi=150, bbox_inches="tight") -print(f"Saved: {snakemake.output[0]}")