rubin-sim 2.6.1.dev2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (387) hide show
  1. batch/compile_prenight_metadata_cache.sh +34 -0
  2. batch/run_auxtel_prenight_sims.sh +163 -0
  3. batch/run_prenight_sims.sh +239 -0
  4. docs/.gitignore +3 -0
  5. docs/Makefile +32 -0
  6. docs/api.rst +25 -0
  7. docs/conf.py +8 -0
  8. docs/data-api.rst +12 -0
  9. docs/data-download.rst +70 -0
  10. docs/developer.rst +14 -0
  11. docs/documenteer.toml +11 -0
  12. docs/index.rst +22 -0
  13. docs/installation.rst +76 -0
  14. docs/introduction.rst +37 -0
  15. docs/maf-api-batches.rst +12 -0
  16. docs/maf-api-db.rst +12 -0
  17. docs/maf-api-maf-contrib.rst +12 -0
  18. docs/maf-api-maps.rst +12 -0
  19. docs/maf-api-metricbundles.rst +12 -0
  20. docs/maf-api-metrics.rst +12 -0
  21. docs/maf-api-plots.rst +12 -0
  22. docs/maf-api-run-comparison.rst +12 -0
  23. docs/maf-api-slicers.rst +12 -0
  24. docs/maf-api-stackers.rst +12 -0
  25. docs/maf-api-utils.rst +12 -0
  26. docs/maf-api.rst +22 -0
  27. docs/maf.rst +60 -0
  28. docs/metric_list.py +49 -0
  29. docs/moving-objects-api.rst +12 -0
  30. docs/moving-objects.rst +22 -0
  31. docs/phot-utils-api.rst +12 -0
  32. docs/phot-utils.rst +11 -0
  33. docs/prenight.rst +117 -0
  34. docs/protoarchive.rst +276 -0
  35. docs/satellite-constellations-api.rst +12 -0
  36. docs/satellite-constellations.rst +13 -0
  37. docs/selfcal-api.rst +12 -0
  38. docs/selfcal.rst +15 -0
  39. docs/sim-archive-api.rst +12 -0
  40. docs/skybrightness-api.rst +12 -0
  41. docs/skybrightness.rst +23 -0
  42. docs/user-guide.rst +28 -0
  43. docs/vseqarchive-architecture.rst +438 -0
  44. docs/vseqarchive-setup.rst +238 -0
  45. docs/vseqarchive.rst +225 -0
  46. rubin_sim/__init__.py +7 -0
  47. rubin_sim/data/__init__.py +1 -0
  48. rubin_sim/data/rs_download_data.py +155 -0
  49. rubin_sim/maf/__init__.py +34 -0
  50. rubin_sim/maf/batches/__init__.py +18 -0
  51. rubin_sim/maf/batches/altaz_batch.py +161 -0
  52. rubin_sim/maf/batches/col_map_dict.py +274 -0
  53. rubin_sim/maf/batches/common.py +388 -0
  54. rubin_sim/maf/batches/ddf_batch.py +728 -0
  55. rubin_sim/maf/batches/filterchange_batch.py +182 -0
  56. rubin_sim/maf/batches/glance_batch.py +591 -0
  57. rubin_sim/maf/batches/hourglass_batch.py +79 -0
  58. rubin_sim/maf/batches/info_batch.py +114 -0
  59. rubin_sim/maf/batches/metadata_batch.py +558 -0
  60. rubin_sim/maf/batches/moving_objects_batch.py +1587 -0
  61. rubin_sim/maf/batches/openshutter_batch.py +100 -0
  62. rubin_sim/maf/batches/radar_limited.py +1100 -0
  63. rubin_sim/maf/batches/science_radar_batch.py +1910 -0
  64. rubin_sim/maf/batches/skycoverage.py +155 -0
  65. rubin_sim/maf/batches/slew_batch.py +146 -0
  66. rubin_sim/maf/batches/srd_batch.py +637 -0
  67. rubin_sim/maf/batches/time_batch.py +757 -0
  68. rubin_sim/maf/batches/time_sci_batch.py +105 -0
  69. rubin_sim/maf/batches/visitdepth_batch.py +485 -0
  70. rubin_sim/maf/db/__init__.py +2 -0
  71. rubin_sim/maf/db/add_run.py +34 -0
  72. rubin_sim/maf/db/results_db.py +1074 -0
  73. rubin_sim/maf/db/tracking_db.py +332 -0
  74. rubin_sim/maf/ddf_dir.py +53 -0
  75. rubin_sim/maf/generate_ss.py +218 -0
  76. rubin_sim/maf/glance_dir.py +58 -0
  77. rubin_sim/maf/maf_contrib/__init__.py +25 -0
  78. rubin_sim/maf/maf_contrib/calculate_lsst_field_visibility_astropy.py +170 -0
  79. rubin_sim/maf/maf_contrib/depth_limited_num_gal_metric.py +109 -0
  80. rubin_sim/maf/maf_contrib/example_new_metrics.py +40 -0
  81. rubin_sim/maf/maf_contrib/filter_pair_t_gaps_metric.py +208 -0
  82. rubin_sim/maf/maf_contrib/grb_transient_metric.py +249 -0
  83. rubin_sim/maf/maf_contrib/gw170817_det_metric.py +72 -0
  84. rubin_sim/maf/maf_contrib/intervals_between_obs_metric.py +68 -0
  85. rubin_sim/maf/maf_contrib/kne_metrics.py +473 -0
  86. rubin_sim/maf/maf_contrib/lss_metrics.py +45 -0
  87. rubin_sim/maf/maf_contrib/lss_obs_strategy/__init__.py +3 -0
  88. rubin_sim/maf/maf_contrib/lss_obs_strategy/constants_for_pipeline.py +73 -0
  89. rubin_sim/maf/maf_contrib/lss_obs_strategy/galaxy_counts_metric_extended.py +205 -0
  90. rubin_sim/maf/maf_contrib/lss_obs_strategy/galaxy_counts_with_pixel_calibration.py +171 -0
  91. rubin_sim/maf/maf_contrib/lv_dwarfs/__init__.py +1 -0
  92. rubin_sim/maf/maf_contrib/lv_dwarfs/lv_dwarfs_metrics.py +388 -0
  93. rubin_sim/maf/maf_contrib/microlensing_metric.py +593 -0
  94. rubin_sim/maf/maf_contrib/num_obs_in_survey_time_overlap_metric.py +43 -0
  95. rubin_sim/maf/maf_contrib/periodic_metric.py +51 -0
  96. rubin_sim/maf/maf_contrib/periodic_star_metric.py +186 -0
  97. rubin_sim/maf/maf_contrib/periodic_star_modulation_metric.py +236 -0
  98. rubin_sim/maf/maf_contrib/presto_color_kne_pop_metric.py +441 -0
  99. rubin_sim/maf/maf_contrib/selfcal_uniformity_metric.py +171 -0
  100. rubin_sim/maf/maf_contrib/star_count_mass_metric.py +64 -0
  101. rubin_sim/maf/maf_contrib/star_count_metric.py +56 -0
  102. rubin_sim/maf/maf_contrib/star_counts/__init__.py +8 -0
  103. rubin_sim/maf/maf_contrib/star_counts/abs_mag.py +324 -0
  104. rubin_sim/maf/maf_contrib/star_counts/coords.py +99 -0
  105. rubin_sim/maf/maf_contrib/star_counts/readme.txt +1 -0
  106. rubin_sim/maf/maf_contrib/star_counts/spec_type.py +91 -0
  107. rubin_sim/maf/maf_contrib/star_counts/starcount.py +30 -0
  108. rubin_sim/maf/maf_contrib/star_counts/starcount_bymass.py +93 -0
  109. rubin_sim/maf/maf_contrib/star_counts/stellardensity.py +59 -0
  110. rubin_sim/maf/maf_contrib/static_probes_fom_summary_metric.py +386 -0
  111. rubin_sim/maf/maf_contrib/tdes_pop_metric.py +362 -0
  112. rubin_sim/maf/maf_contrib/transient_ascii_sed_metric.py +652 -0
  113. rubin_sim/maf/maf_contrib/triplet_metric.py +156 -0
  114. rubin_sim/maf/maf_contrib/var_depth_metric.py +157 -0
  115. rubin_sim/maf/maf_contrib/xrb_metrics.py +523 -0
  116. rubin_sim/maf/maf_contrib/young_stellar_objects_metric.py +200 -0
  117. rubin_sim/maf/maf_night_report.py +200 -0
  118. rubin_sim/maf/make_fbs_tracking_db.py +90 -0
  119. rubin_sim/maf/maps/__init__.py +8 -0
  120. rubin_sim/maf/maps/base_map.py +72 -0
  121. rubin_sim/maf/maps/create_gaia_density_map.py +158 -0
  122. rubin_sim/maf/maps/dust_map.py +66 -0
  123. rubin_sim/maf/maps/dust_map_3d.py +190 -0
  124. rubin_sim/maf/maps/ebv_3d_hp.py +170 -0
  125. rubin_sim/maf/maps/ebv_hp.py +64 -0
  126. rubin_sim/maf/maps/gal_coords_map.py +22 -0
  127. rubin_sim/maf/maps/galactic_plane_priority_maps.py +210 -0
  128. rubin_sim/maf/maps/stellar_density_map.py +73 -0
  129. rubin_sim/maf/maps/trilegal_map.py +82 -0
  130. rubin_sim/maf/metadata_dir.py +90 -0
  131. rubin_sim/maf/metric_bundles/__init__.py +3 -0
  132. rubin_sim/maf/metric_bundles/metric_bundle.py +816 -0
  133. rubin_sim/maf/metric_bundles/metric_bundle_group.py +834 -0
  134. rubin_sim/maf/metric_bundles/mo_metric_bundle.py +646 -0
  135. rubin_sim/maf/metrics/__init__.py +52 -0
  136. rubin_sim/maf/metrics/agn_time_lag_metric.py +118 -0
  137. rubin_sim/maf/metrics/agnstructure.py +141 -0
  138. rubin_sim/maf/metrics/area_summary_metrics.py +120 -0
  139. rubin_sim/maf/metrics/base_metric.py +215 -0
  140. rubin_sim/maf/metrics/brown_dwarf_metric.py +162 -0
  141. rubin_sim/maf/metrics/cadence_metrics.py +400 -0
  142. rubin_sim/maf/metrics/calibration_metrics.py +618 -0
  143. rubin_sim/maf/metrics/chip_vendor_metric.py +43 -0
  144. rubin_sim/maf/metrics/color_slope_metrics.py +189 -0
  145. rubin_sim/maf/metrics/cosmology_summary_metrics.py +1212 -0
  146. rubin_sim/maf/metrics/coverage_metric.py +48 -0
  147. rubin_sim/maf/metrics/crowding_metric.py +255 -0
  148. rubin_sim/maf/metrics/cumulative_metric.py +46 -0
  149. rubin_sim/maf/metrics/dcr_metric.py +93 -0
  150. rubin_sim/maf/metrics/exgal_m5.py +57 -0
  151. rubin_sim/maf/metrics/fft_metric.py +27 -0
  152. rubin_sim/maf/metrics/galactic_plane_metrics.py +375 -0
  153. rubin_sim/maf/metrics/galplane_time_sampling_metrics.py +236 -0
  154. rubin_sim/maf/metrics/hourglass_metric.py +130 -0
  155. rubin_sim/maf/metrics/incremental_template_metric.py +255 -0
  156. rubin_sim/maf/metrics/kuiper_metrics.py +26 -0
  157. rubin_sim/maf/metrics/mo_metrics.py +1496 -0
  158. rubin_sim/maf/metrics/mo_summary_metrics.py +464 -0
  159. rubin_sim/maf/metrics/night_pointing_metric.py +70 -0
  160. rubin_sim/maf/metrics/optimal_m5_metric.py +94 -0
  161. rubin_sim/maf/metrics/pair_metric.py +69 -0
  162. rubin_sim/maf/metrics/periodic_detect_metric.py +133 -0
  163. rubin_sim/maf/metrics/phase_gap_metric.py +172 -0
  164. rubin_sim/maf/metrics/qso_number_counts_metric.py +138 -0
  165. rubin_sim/maf/metrics/scaling_metrics.py +148 -0
  166. rubin_sim/maf/metrics/schedview_metrics.py +39 -0
  167. rubin_sim/maf/metrics/season_metrics.py +344 -0
  168. rubin_sim/maf/metrics/simple_metrics.py +546 -0
  169. rubin_sim/maf/metrics/sky_sat_metric.py +18 -0
  170. rubin_sim/maf/metrics/sn_cadence_metric.py +104 -0
  171. rubin_sim/maf/metrics/sn_n_sn_metric.py +1364 -0
  172. rubin_sim/maf/metrics/sn_sl_metric.py +216 -0
  173. rubin_sim/maf/metrics/sn_snr_metric.py +715 -0
  174. rubin_sim/maf/metrics/snr_weight.py +24 -0
  175. rubin_sim/maf/metrics/star_density.py +77 -0
  176. rubin_sim/maf/metrics/string_count_metric.py +95 -0
  177. rubin_sim/maf/metrics/summary_metrics.py +201 -0
  178. rubin_sim/maf/metrics/surfb_metric.py +175 -0
  179. rubin_sim/maf/metrics/technical_metrics.py +271 -0
  180. rubin_sim/maf/metrics/tgaps.py +412 -0
  181. rubin_sim/maf/metrics/tomography_models.py +2034 -0
  182. rubin_sim/maf/metrics/transient_metrics.py +268 -0
  183. rubin_sim/maf/metrics/uniformity_metrics.py +418 -0
  184. rubin_sim/maf/metrics/use_metrics.py +55 -0
  185. rubin_sim/maf/metrics/vector_metrics.py +190 -0
  186. rubin_sim/maf/metrics/visit_groups_metric.py +341 -0
  187. rubin_sim/maf/metrics/weak_lensing_systematics_metric.py +210 -0
  188. rubin_sim/maf/plots/__init__.py +14 -0
  189. rubin_sim/maf/plots/hg_plotters.py +1117 -0
  190. rubin_sim/maf/plots/hourglass_plotters.py +120 -0
  191. rubin_sim/maf/plots/mo_plotters.py +358 -0
  192. rubin_sim/maf/plots/nd_plotters.py +220 -0
  193. rubin_sim/maf/plots/neo_distance_plotter.py +140 -0
  194. rubin_sim/maf/plots/night_pointing_plotter.py +96 -0
  195. rubin_sim/maf/plots/oned_plotters.py +114 -0
  196. rubin_sim/maf/plots/perceptual_rainbow.py +30 -0
  197. rubin_sim/maf/plots/plot_handler.py +766 -0
  198. rubin_sim/maf/plots/skyproj_plotters.py +540 -0
  199. rubin_sim/maf/plots/spatial_plotters.py +1029 -0
  200. rubin_sim/maf/plots/special_plotters.py +256 -0
  201. rubin_sim/maf/plots/two_d_plotters.py +177 -0
  202. rubin_sim/maf/plots/xyplotter.py +37 -0
  203. rubin_sim/maf/run_comparison/__init__.py +5 -0
  204. rubin_sim/maf/run_comparison/archive.py +584 -0
  205. rubin_sim/maf/run_comparison/gather_summaries.py +125 -0
  206. rubin_sim/maf/run_comparison/microlensing_compare.py +514 -0
  207. rubin_sim/maf/run_comparison/radar_plot.py +202 -0
  208. rubin_sim/maf/run_comparison/summary_plots.py +710 -0
  209. rubin_sim/maf/run_moving_calc.py +239 -0
  210. rubin_sim/maf/run_moving_fractions.py +128 -0
  211. rubin_sim/maf/run_moving_join.py +103 -0
  212. rubin_sim/maf/run_selfcal_metric.py +92 -0
  213. rubin_sim/maf/scimaf_dir.py +87 -0
  214. rubin_sim/maf/show_maf.py +227 -0
  215. rubin_sim/maf/slicers/__init__.py +13 -0
  216. rubin_sim/maf/slicers/base_slicer.py +513 -0
  217. rubin_sim/maf/slicers/base_spatial_slicer.py +202 -0
  218. rubin_sim/maf/slicers/healpix_sdss_slicer.py +118 -0
  219. rubin_sim/maf/slicers/healpix_slicer.py +189 -0
  220. rubin_sim/maf/slicers/healpix_subset_slicer.py +293 -0
  221. rubin_sim/maf/slicers/hourglass_slicer.py +37 -0
  222. rubin_sim/maf/slicers/mo_slicer.py +171 -0
  223. rubin_sim/maf/slicers/movie_slicer.py +288 -0
  224. rubin_sim/maf/slicers/nd_slicer.py +147 -0
  225. rubin_sim/maf/slicers/one_d_slicer.py +210 -0
  226. rubin_sim/maf/slicers/time_interval_slicers.py +283 -0
  227. rubin_sim/maf/slicers/uni_slicer.py +57 -0
  228. rubin_sim/maf/slicers/user_points_slicer.py +141 -0
  229. rubin_sim/maf/stackers/__init__.py +13 -0
  230. rubin_sim/maf/stackers/base_stacker.py +221 -0
  231. rubin_sim/maf/stackers/coord_stackers.py +224 -0
  232. rubin_sim/maf/stackers/date_stackers.py +192 -0
  233. rubin_sim/maf/stackers/general_stackers.py +683 -0
  234. rubin_sim/maf/stackers/get_col_info.py +104 -0
  235. rubin_sim/maf/stackers/label_stackers.py +114 -0
  236. rubin_sim/maf/stackers/m5_optimal_stacker.py +126 -0
  237. rubin_sim/maf/stackers/mo_phase.py +265 -0
  238. rubin_sim/maf/stackers/mo_stackers.py +486 -0
  239. rubin_sim/maf/stackers/n_follow_stacker.py +187 -0
  240. rubin_sim/maf/stackers/neo_dist_stacker.py +126 -0
  241. rubin_sim/maf/stackers/sdss_stackers.py +30 -0
  242. rubin_sim/maf/stackers/sn_stacker.py +152 -0
  243. rubin_sim/maf/stackers/teff_stacker.py +154 -0
  244. rubin_sim/maf/utils/__init__.py +6 -0
  245. rubin_sim/maf/utils/astrometry_utils.py +93 -0
  246. rubin_sim/maf/utils/generate_fov_map.py +58 -0
  247. rubin_sim/maf/utils/get_date_version.py +28 -0
  248. rubin_sim/maf/utils/maf_utils.py +212 -0
  249. rubin_sim/maf/utils/opsim_utils.py +259 -0
  250. rubin_sim/maf/utils/output_utils.py +34 -0
  251. rubin_sim/maf/utils/sn_n_sn_utils.py +894 -0
  252. rubin_sim/maf/utils/sn_utils.py +369 -0
  253. rubin_sim/maf/utils/stellar_mags.py +197 -0
  254. rubin_sim/maf/web/__init__.py +2 -0
  255. rubin_sim/maf/web/favicon.ico +0 -0
  256. rubin_sim/maf/web/maf_run_results.py +645 -0
  257. rubin_sim/maf/web/maf_tracking.py +139 -0
  258. rubin_sim/maf/web/sorttable.js +496 -0
  259. rubin_sim/maf/web/templates/allmetricresults.html +72 -0
  260. rubin_sim/maf/web/templates/configs.html +28 -0
  261. rubin_sim/maf/web/templates/macros.html +243 -0
  262. rubin_sim/maf/web/templates/master.html +294 -0
  263. rubin_sim/maf/web/templates/metricselect.html +91 -0
  264. rubin_sim/maf/web/templates/multicolor.html +147 -0
  265. rubin_sim/maf/web/templates/results.html +82 -0
  266. rubin_sim/maf/web/templates/runselect.html +58 -0
  267. rubin_sim/maf/web/templates/stats.html +50 -0
  268. rubin_sim/moving_objects/__init__.py +8 -0
  269. rubin_sim/moving_objects/base_obs.py +468 -0
  270. rubin_sim/moving_objects/cheby_fits.py +689 -0
  271. rubin_sim/moving_objects/cheby_values.py +231 -0
  272. rubin_sim/moving_objects/chebyshev_utils.py +365 -0
  273. rubin_sim/moving_objects/direct_obs.py +376 -0
  274. rubin_sim/moving_objects/make_lsst_obs.py +282 -0
  275. rubin_sim/moving_objects/ooephemerides.py +643 -0
  276. rubin_sim/moving_objects/orbits.py +507 -0
  277. rubin_sim/moving_objects/pre_generate.py +37 -0
  278. rubin_sim/moving_objects/utils.py +61 -0
  279. rubin_sim/phot_utils/__init__.py +7 -0
  280. rubin_sim/phot_utils/bandpass.py +425 -0
  281. rubin_sim/phot_utils/photometric_parameters.py +449 -0
  282. rubin_sim/phot_utils/physical_parameters.py +50 -0
  283. rubin_sim/phot_utils/predicted_zeropoints.py +245 -0
  284. rubin_sim/phot_utils/sed.py +1773 -0
  285. rubin_sim/phot_utils/sed_utils.py +52 -0
  286. rubin_sim/phot_utils/signaltonoise.py +695 -0
  287. rubin_sim/phot_utils/spectral_resampling.py +161 -0
  288. rubin_sim/satellite_constellations/__init__.py +3 -0
  289. rubin_sim/satellite_constellations/basis_function.py +40 -0
  290. rubin_sim/satellite_constellations/model_observatory.py +157 -0
  291. rubin_sim/satellite_constellations/sat_utils.py +488 -0
  292. rubin_sim/selfcal/__init__.py +4 -0
  293. rubin_sim/selfcal/generate_catalog.py +188 -0
  294. rubin_sim/selfcal/offsets.py +119 -0
  295. rubin_sim/selfcal/solver.py +143 -0
  296. rubin_sim/selfcal/star_tools.py +42 -0
  297. rubin_sim/sim_archive/__init__.py +14 -0
  298. rubin_sim/sim_archive/conda_packages.py +65 -0
  299. rubin_sim/sim_archive/future_vsarch.py +480 -0
  300. rubin_sim/sim_archive/make_snapshot.py +255 -0
  301. rubin_sim/sim_archive/prenight.py +216 -0
  302. rubin_sim/sim_archive/prenightindex.py +229 -0
  303. rubin_sim/sim_archive/prototype.py +1029 -0
  304. rubin_sim/sim_archive/sim_archive.py +680 -0
  305. rubin_sim/sim_archive/tempdb.py +56 -0
  306. rubin_sim/sim_archive/util.py +146 -0
  307. rubin_sim/sim_archive/vseqarchive.py +965 -0
  308. rubin_sim/sim_archive/vseqmetadata.py +1721 -0
  309. rubin_sim/skybrightness/__init__.py +5 -0
  310. rubin_sim/skybrightness/allsky_db.py +93 -0
  311. rubin_sim/skybrightness/data/ESO_Spectra/eso_tools.py +505 -0
  312. rubin_sim/skybrightness/data/solarSpec/package.py +22 -0
  313. rubin_sim/skybrightness/generate_hdf5.py +243 -0
  314. rubin_sim/skybrightness/interp_components.py +798 -0
  315. rubin_sim/skybrightness/sky_model.py +771 -0
  316. rubin_sim/skybrightness/twilight_func.py +83 -0
  317. rubin_sim/skybrightness/utils.py +91 -0
  318. rubin_sim-2.6.1.dev2.dist-info/METADATA +95 -0
  319. rubin_sim-2.6.1.dev2.dist-info/RECORD +387 -0
  320. rubin_sim-2.6.1.dev2.dist-info/WHEEL +5 -0
  321. rubin_sim-2.6.1.dev2.dist-info/entry_points.txt +24 -0
  322. rubin_sim-2.6.1.dev2.dist-info/licenses/LICENSE +674 -0
  323. rubin_sim-2.6.1.dev2.dist-info/top_level.txt +5 -0
  324. sql/make_vseqmeta.sql +251 -0
  325. tests/data/test_data.py +26 -0
  326. tests/data/test_ddf_grid.py +17 -0
  327. tests/maf/test_3x2fom.py +68 -0
  328. tests/maf/test_archive.py +162 -0
  329. tests/maf/test_basemetrics.py +99 -0
  330. tests/maf/test_batchcommon.py +36 -0
  331. tests/maf/test_batches.py +159 -0
  332. tests/maf/test_cadencemetrics.py +388 -0
  333. tests/maf/test_calibrationmetrics.py +242 -0
  334. tests/maf/test_color_slopes.py +71 -0
  335. tests/maf/test_cosmology_summaries.py +20 -0
  336. tests/maf/test_gathersummaries.py +48 -0
  337. tests/maf/test_healpixslicer.py +439 -0
  338. tests/maf/test_healpixsubsetslicer.py +273 -0
  339. tests/maf/test_hgplotters.py +145 -0
  340. tests/maf/test_hourglassmetric.py +33 -0
  341. tests/maf/test_io.py +187 -0
  342. tests/maf/test_json.py +169 -0
  343. tests/maf/test_maps.py +199 -0
  344. tests/maf/test_metricbundle.py +69 -0
  345. tests/maf/test_mometrics.py +422 -0
  346. tests/maf/test_movieslicer.py +216 -0
  347. tests/maf/test_ndslicer.py +240 -0
  348. tests/maf/test_neodistanceplotter.py +41 -0
  349. tests/maf/test_onedslicer.py +245 -0
  350. tests/maf/test_opsimutils.py +80 -0
  351. tests/maf/test_plotters.py +134 -0
  352. tests/maf/test_resultsdb.py +145 -0
  353. tests/maf/test_schedviewmetrics.py +14 -0
  354. tests/maf/test_simplemetrics.py +200 -0
  355. tests/maf/test_snmetrics.py +335 -0
  356. tests/maf/test_snmetrics_nsn.py +123 -0
  357. tests/maf/test_stackers.py +423 -0
  358. tests/maf/test_stellarmags.py +50 -0
  359. tests/maf/test_stringcount.py +26 -0
  360. tests/maf/test_summary_plots.py +197 -0
  361. tests/maf/test_summarymetrics.py +82 -0
  362. tests/maf/test_technicalmetrics.py +267 -0
  363. tests/maf/test_templatemetrics.py +86 -0
  364. tests/maf/test_timeintervalslicers.py +97 -0
  365. tests/maf/test_trackingdb.py +88 -0
  366. tests/maf/test_unislicer.py +116 -0
  367. tests/maf/test_vectormetrics.py +225 -0
  368. tests/maf/test_visitgroupsmetric.py +181 -0
  369. tests/moving_objects/test_camera.py +39 -0
  370. tests/moving_objects/test_chebyfits.py +188 -0
  371. tests/moving_objects/test_chebyshevutils.py +76 -0
  372. tests/moving_objects/test_chebyvalues.py +245 -0
  373. tests/moving_objects/test_ephemerides.py +219 -0
  374. tests/moving_objects/test_orbits.py +170 -0
  375. tests/moving_objects/test_sed_data.py +61 -0
  376. tests/phot_utils/test_approximatebandpasses.py +91 -0
  377. tests/phot_utils/test_photometricparameters.py +268 -0
  378. tests/phot_utils/test_photometry.py +61 -0
  379. tests/phot_utils/test_predicted_zeropoints.py +53 -0
  380. tests/phot_utils/test_read_bandpasses.py +29 -0
  381. tests/phot_utils/test_sed.py +368 -0
  382. tests/phot_utils/test_snr.py +370 -0
  383. tests/satellite_constellations/test_satellites.py +36 -0
  384. tests/sim_archive/test_make_snapshot.py +24 -0
  385. tests/sim_archive/test_prototype_sim_archive.py +204 -0
  386. tests/sim_archive/test_vseqarchive.py +947 -0
  387. tests/skybrightness/test_skymodel.py +359 -0
@@ -0,0 +1,1364 @@
1
+ __all__ = ("SNNSNMetric",)
2
+
3
+
4
+ import healpy as hp
5
+ import numpy as np
6
+ import numpy.lib.recfunctions as nlr
7
+ import pandas as pd
8
+ from scipy.interpolate import interp1d
9
+
10
+ from rubin_sim.maf.metrics import BaseMetric
11
+ from rubin_sim.maf.utils.sn_n_sn_utils import LcfastNew, SnRate, load_sne_cached
12
+ from rubin_sim.phot_utils import DustValues
13
+
14
+
15
+ class SNNSNMetric(BaseMetric):
16
+ """
17
+ Measure zlim of type Ia supernovae.
18
+
19
+ Parameters
20
+ --------------
21
+ metricName : `str`, opt
22
+ metric name (default : SNSNRMetric)
23
+ mjd_col : `str`, opt
24
+ mjd column name (default : observationStartMJD)
25
+ filter_col : `str`, opt
26
+ filter column name (default: filter)
27
+ m5_col : `str`, opt
28
+ five-sigma depth column name (default : fiveSigmaDepth)
29
+ exptime_col : `str`, opt
30
+ exposure time column name (default : visitExposureTime)
31
+ night_col : `str`, opt
32
+ night column name (default : night)
33
+ obsid_col : `str`, opt
34
+ observation id column name (default : observationId)
35
+ nexp_col : `str`, opt
36
+ number of exposure column name (default : numExposures)
37
+ vistime_col : `str`, opt
38
+ visit time column name (default : visitTime)
39
+ seeing_col : `str`, opt
40
+ seeing column name (default: seeingFwhmEff)
41
+ note_col : `str`, opt
42
+ note column name (default: scheduler_note)
43
+ season : `list`, opt
44
+ list of seasons to process (float)(default: -1 = all seasons)
45
+ coadd : `bool`, opt
46
+ coaddition per night (and per band) (default : True)
47
+ zmin : `float`, opt
48
+ min redshift for the study (default: 0.0)
49
+ zmax : `float`, opt
50
+ max redshift for the study (default: 1.2)
51
+ verbose : `bool`, opt
52
+ verbose mode (default: False)
53
+ n_bef : `int`, opt
54
+ number of LC points LC before T0 (default:5)
55
+ n_aft : `int`, opt
56
+ number of LC points after T0 (default: 10)
57
+ snr_min : `float`, opt
58
+ minimal SNR of LC points (default: 5.0)
59
+ n_phase_min : `int`, opt
60
+ number of LC points with phase<= -5(default:1)
61
+ n_phase_max : `int`, opt
62
+ number of LC points with phase>= 20 (default: 1)
63
+ zlim_coeff: float, opt
64
+ corresponds to the zlim_coeff fraction of SN with z<zlim
65
+ bands : `str`, opt
66
+ bands to consider (default: grizy)
67
+ gammaName: `str`, opt
68
+ name of the gamma ref file to load (default: gamma_WFD.hdf5)
69
+ dust : `bool`, opt
70
+ Apply dust extinction to visit depth values (default False)
71
+ hard_dust_cut : `float`, opt
72
+ If set, cut any point on the sky that has an ebv extinction
73
+ higher than the hard_dust_cut value.
74
+ Default 0.25
75
+ """
76
+
77
+ def __init__(
78
+ self,
79
+ metric_name="SNNSNMetric",
80
+ mjd_col="observationStartMJD",
81
+ filter_col="band",
82
+ m5_col="fiveSigmaDepth",
83
+ exptime_col="visitExposureTime",
84
+ night_col="night",
85
+ obsid_col="observationId",
86
+ nexp_col="numExposures",
87
+ vistime_col="visitTime",
88
+ seeing_col="seeingFwhmEff",
89
+ note_col="scheduler_note",
90
+ season=[-1],
91
+ coadd_night=True,
92
+ zmin=0.1,
93
+ zmax=0.5,
94
+ z_step=0.03,
95
+ daymax_step=3.0,
96
+ verbose=False,
97
+ ploteffi=False,
98
+ n_bef=3,
99
+ n_aft=8,
100
+ snr_min=1.0,
101
+ n_phase_min=1,
102
+ n_phase_max=1,
103
+ sigma_c=0.04,
104
+ zlim_coeff=0.95,
105
+ bands="grizy",
106
+ add_dust=False,
107
+ hard_dust_cut=0.25,
108
+ gamma_name="gamma_WFD.hdf5",
109
+ **kwargs,
110
+ ):
111
+ # n_bef / n_aft = 3/8 for WFD, 4/10 for DDF
112
+
113
+ self.mjd_col = mjd_col
114
+ self.m5_col = m5_col
115
+ self.filter_col = filter_col
116
+ self.exptime_col = exptime_col
117
+ self.season_col = "season"
118
+ self.night_col = night_col
119
+ self.obsid_col = obsid_col
120
+ self.nexp_col = nexp_col
121
+ self.vistime_col = vistime_col
122
+ self.seeing_col = seeing_col
123
+ self.note_col = note_col
124
+
125
+ self.ploteffi = ploteffi
126
+ self.t0s = "all"
127
+ self.zlim_coeff = zlim_coeff
128
+ self.bands = bands
129
+ self.coadd_night = coadd_night
130
+ self.add_dust = add_dust
131
+ self.hard_dust_cut = hard_dust_cut
132
+
133
+ maps = ["DustMap"]
134
+ dust_properties = DustValues()
135
+ self.ax1 = dust_properties.ax1
136
+
137
+ cols = [
138
+ self.night_col,
139
+ self.m5_col,
140
+ self.filter_col,
141
+ self.mjd_col,
142
+ self.obsid_col,
143
+ self.nexp_col,
144
+ self.vistime_col,
145
+ self.exptime_col,
146
+ self.note_col,
147
+ ]
148
+
149
+ super(SNNSNMetric, self).__init__(
150
+ col=cols,
151
+ metric_dtype="object",
152
+ metric_name=metric_name,
153
+ maps=maps,
154
+ **kwargs,
155
+ )
156
+
157
+ self.season = season
158
+
159
+ # LC selection parameters
160
+ self.n_bef = n_bef # nb points before peak
161
+ self.n_aft = n_aft # nb points after peak
162
+ self.snr_min = snr_min # SNR cut for points before/after peak
163
+ self.n_phase_min = n_phase_min # nb of point with phase <=-5
164
+ self.n_phase_max = n_phase_max # nb of points with phase >=20
165
+ self.sigma_c = sigma_c
166
+
167
+ # loading reference LC files
168
+ lc_reference = load_sne_cached(gamma_name)
169
+ # loading reference LC files
170
+
171
+ self.lc_fast = {}
172
+ for key, vals in lc_reference.items():
173
+ self.lc_fast[key] = LcfastNew(
174
+ vals,
175
+ key[0],
176
+ key[1],
177
+ self.mjd_col,
178
+ self.filter_col,
179
+ self.exptime_col,
180
+ self.m5_col,
181
+ self.season_col,
182
+ self.nexp_col,
183
+ self.seeing_col,
184
+ self.snr_min,
185
+ light_output=False,
186
+ )
187
+ # loading parameters
188
+ self.zmin = zmin # zmin for the study
189
+ self.zmax = zmax # zmax for the study
190
+ self.zstep = z_step # zstep
191
+ # get redshift range for processing
192
+ zrange = list(np.arange(self.zmin, self.zmax, self.zstep))
193
+ if zrange[0] < 1.0e-6:
194
+ zrange[0] = 0.01
195
+
196
+ self.zrange = np.unique(zrange)
197
+
198
+ self.daymax_step = daymax_step # daymax step
199
+ self.min_rf_phase = -20.0 # min ref phase for LC points selection
200
+ self.max_rf_phase = 60.0 # max ref phase for LC points selection
201
+
202
+ self.min_rf_phase_qual = -15.0 # min ref phase for bounds effects
203
+ self.max_rf_phase_qual = 30.0 # max ref phase for bounds effects
204
+
205
+ # snrate
206
+ self.rate_sn = SnRate(
207
+ h0=70.0,
208
+ om0=0.3,
209
+ min_rf_phase=self.min_rf_phase_qual,
210
+ max_rf_phase=self.max_rf_phase_qual,
211
+ )
212
+
213
+ # verbose mode - useful for debug and code performance estimation
214
+ self.verbose = verbose
215
+
216
+ # supernovae parameters for fisher estimation
217
+ self.params = ["x0", "x1", "daymax", "color"]
218
+
219
+ def run(self, data_slice, slice_point):
220
+ """
221
+ Run method of the metric
222
+
223
+ Parameters
224
+ --------------
225
+ data_slice : `np.ndarray`
226
+ Observations to process (scheduler simulations)
227
+ slice_point : `bool`, opt
228
+ Information about the location on the sky from the slicer
229
+
230
+ Returns
231
+ -------
232
+ metricVal : `np.ndarray`
233
+ ['n_sn', 'zlim'] at this point on the sky
234
+ """
235
+ # Hard dust cut
236
+ if self.hard_dust_cut is not None:
237
+ ebvof_mw = slice_point["ebv"]
238
+ if ebvof_mw > self.hard_dust_cut:
239
+ return self.badval
240
+
241
+ # get area on-sky in this slice_point
242
+ if "nside" in slice_point:
243
+ self.pix_area = hp.nside2pixarea(slice_point["nside"], degrees=True)
244
+ else:
245
+ self.pix_area = 9.6
246
+
247
+ # If we want to apply dust extinction.
248
+ if self.add_dust:
249
+ new_m5 = data_slice[self.m5_col] * 0
250
+ for filtername in np.unique(data_slice[self.filter_col]):
251
+ in_filt = np.where(data_slice[self.filter_col] == filtername)[0]
252
+ a_x = self.ax1[filtername] * slice_point["ebv"]
253
+ new_m5[in_filt] = data_slice[self.m5_col][in_filt] - a_x
254
+ data_slice[self.m5_col] = new_m5
255
+
256
+ # select observations filter
257
+ good_filters = np.isin(data_slice[self.filter_col], list(self.bands))
258
+ data_slice = data_slice[good_filters]
259
+
260
+ # coaddition per night and per band (if requested by the user)
261
+ if self.coadd_night:
262
+ data_slice = self.coadd(data_slice)
263
+
264
+ # This seems unlikely, but is a possible bailout point
265
+ if len(data_slice) <= self.n_aft + self.n_bef:
266
+ return self.badval
267
+
268
+ # get season information (seasons calculated by gaps,
269
+ # not by place on sky)
270
+ data_slice = self.getseason(data_slice, mjd_col=self.mjd_col)
271
+
272
+ # get redshift values per season
273
+ zseason = self.z_season(self.season, data_slice)
274
+ zseason_allz = self.z_season_allz(zseason)
275
+
276
+ # estimate redshift completeness
277
+ metric_values = self.metric(data_slice, zseason_allz, x1=-2.0, color=0.2, zlim=-1, metric="zlim")
278
+
279
+ if metric_values is None:
280
+ return self.badval
281
+
282
+ if np.max(metric_values["zcomp"]) < 0:
283
+ return self.badval
284
+
285
+ # get redshift values per season up to zcomp
286
+ zseason = pd.DataFrame(metric_values[["season", "zcomp"]])
287
+ zseason.loc[:, "zmin"] = 0.01
288
+ zseason.loc[:, "zstep"] = self.zstep
289
+ zseason = zseason.rename(columns={"zcomp": "zmax"})
290
+ zseason["zmax"] += self.zstep
291
+ zseason_allz = self.z_season_allz(zseason)
292
+
293
+ # get the total number of well-sampled SN up to zcomp
294
+ nsn_zcomp = self.metric(
295
+ data_slice,
296
+ zseason_allz,
297
+ x1=0.0,
298
+ color=0.0,
299
+ zlim=metric_values[["season", "zcomp"]],
300
+ metric="nsn",
301
+ )
302
+
303
+ # final results
304
+ if nsn_zcomp is None:
305
+ return self.badval
306
+ metric_values = metric_values.merge(nsn_zcomp, left_on=["season"], right_on=["season"])
307
+
308
+ if self.verbose:
309
+ print("metric_values", metric_values[["season", "zcomp", "nsn"]])
310
+
311
+ idx = metric_values["zcomp"] > 0.0
312
+ selmet = metric_values[idx]
313
+
314
+ if len(selmet) > 0:
315
+ zcomp = selmet["zcomp"].median()
316
+ n_sn = selmet["nsn"].sum()
317
+ res = np.rec.fromrecords([(n_sn, zcomp)], names=["n_sn", "zlim"])
318
+ else:
319
+ res = self.badval
320
+
321
+ if self.verbose:
322
+ print("final result", res)
323
+
324
+ return res
325
+
326
+ def season_length(self, seasons, data_slice, zseason):
327
+ """
328
+ Method to estimate season lengths vs z
329
+
330
+ Parameters
331
+ -----------
332
+ seasons : `list` [`int`]
333
+ list of seasons to process
334
+ data_slice : `np.ndarray`, (N,)`
335
+ array of observations
336
+ zseason : `pd.DataFrame`
337
+ redshift infos per season
338
+
339
+ Returns
340
+ --------
341
+ seasons : `list` [`int`]
342
+ list of seasons to process
343
+ dur_z : `pd.DataFrame`
344
+ season lengths vs z
345
+ """
346
+ # if seasons = -1: process the seasons seen in data
347
+ if seasons == [-1]:
348
+ seasons = np.unique(data_slice[self.season_col])
349
+
350
+ # season infos
351
+ dfa = pd.DataFrame(np.copy(data_slice))
352
+ dfa = pd.DataFrame(dfa[dfa["season"].isin(seasons)])
353
+
354
+ season_info = self.get_season_info(dfa, zseason)
355
+
356
+ if self.verbose:
357
+ print("season_info", season_info)
358
+
359
+ if season_info.empty:
360
+ return [], pd.DataFrame()
361
+
362
+ season_info["season_copy"] = season_info["season"].values.copy()
363
+ dur_z = (
364
+ season_info.groupby("season_copy", group_keys=False)
365
+ .apply(lambda x: self.nsn_expected_z(x), include_groups=False)
366
+ .reset_index(drop=True)
367
+ )
368
+ return season_info["season"].to_list(), dur_z
369
+
370
+ def get_season_info(self, dfa, zseason, min_duration=60.0):
371
+ """
372
+ method to get season infos vs z
373
+
374
+ Parameters
375
+ --------------
376
+ dfa : `pd.DataFrame`
377
+ data to process
378
+ zseason : `pd.DataFrame`
379
+ redshift infos per season
380
+ min_duration : `float`, opt
381
+ min season length to be accepted (default: 60 days)
382
+
383
+ Returns
384
+ --------
385
+ season_info : `pd.DataFrame` with season length infos
386
+
387
+ """
388
+ dfa["season_copy"] = dfa["season"].values.copy()
389
+ season_info = (
390
+ dfa.groupby("season")
391
+ .apply(lambda x: self.season_info(x, min_duration=min_duration), include_groups=False)
392
+ .reset_index()
393
+ )
394
+
395
+ # season_info.index = season_info.index.droplevel()
396
+ season_info = season_info.drop(columns=["level_1"])
397
+
398
+ season_info = season_info.merge(zseason, left_on=["season"], right_on=["season"])
399
+
400
+ season_info["T0_min"] = season_info["MJD_min"] - (1.0 + season_info["z"]) * self.min_rf_phase_qual
401
+ season_info["T0_max"] = season_info["MJD_max"] - (1.0 + season_info["z"]) * self.max_rf_phase_qual
402
+ season_info["season_length"] = season_info["T0_max"] - season_info["T0_min"]
403
+
404
+ idx = season_info["season_length"] >= min_duration
405
+
406
+ return pd.DataFrame(season_info[idx])
407
+
408
+ def step_lc(self, obs, gen_par, x1=-2.0, color=0.2):
409
+ """
410
+ Method to generate lc
411
+
412
+ Parameters
413
+ ---------------
414
+ obs : array
415
+ observations
416
+ gen_par : array
417
+ simulation parameters
418
+ x1 : `float`, opt
419
+ stretch value (default: -2.0)
420
+ color : `float`, opt
421
+ color value (default: 0.2)
422
+
423
+ Returns
424
+ ----------
425
+ SN light curves (astropy table)
426
+
427
+ """
428
+ obs["season_copy"] = obs["season"].values.copy()
429
+ lc = obs.groupby(["season_copy"]).apply(
430
+ lambda x: self.gen_lc(x, gen_par, x1, color), include_groups=False
431
+ )
432
+ return lc
433
+
434
+ def step_efficiencies(self, lc):
435
+ """
436
+ Method to estimate observing efficiencies
437
+
438
+ Parameter
439
+ -------------
440
+ lc: `pd.DataFrame`
441
+ light curves
442
+
443
+ Returns
444
+ -----------
445
+ `pd.DataFrame` with efficiencies
446
+
447
+ """
448
+ cols = ["season", "z", "x1", "color", "sntype"]
449
+ for col in cols:
450
+ lc[col + "_copy"] = lc[col].values.copy()
451
+
452
+ sn_effis = lc.groupby(cols).apply(lambda x: self.sn_effi(x), include_groups=False).reset_index()
453
+
454
+ # estimate efficiencies
455
+ sn_effis["season"] = sn_effis["season"].astype(int)
456
+ sn_effis["effi"] = sn_effis["nsel"] / sn_effis["ntot"]
457
+ sn_effis["effi_err"] = np.sqrt(sn_effis["nsel"] * (1.0 - sn_effis["effi"])) / sn_effis["ntot"]
458
+
459
+ # prevent NaNs, set effi to 0 where there is 0 ntot
460
+ zero = np.where(sn_effis["ntot"] == 0)
461
+ sn_effis["effi"].values[zero] = 0
462
+ sn_effis["effi_err"].values[zero] = 0
463
+
464
+ if self.verbose:
465
+ for season in sn_effis["season"].unique():
466
+ idx = sn_effis["season"] == season
467
+ print("effis", sn_effis[idx])
468
+
469
+ if self.ploteffi:
470
+ from sn_metrics.sn_plot_live import plotNSN_effi
471
+
472
+ for season in sn_effis["season"].unique():
473
+ idx = sn_effis["season"] == season
474
+ print("effis", sn_effis[idx])
475
+ plotNSN_effi(sn_effis[idx], "effi", "effi_err", "Observing Efficiencies", ls="-")
476
+
477
+ return sn_effis
478
+
479
+ def step_nsn(self, sn_effis, dur_z):
480
+ """
481
+ Method to estimate the number of supernovae from efficiencies
482
+
483
+ Parameters
484
+ ----------
485
+ sn_effis : `pd.DataFrame`
486
+ data with efficiencies of observation
487
+ dur_z : array
488
+ array of season length
489
+
490
+ Returns
491
+ -------
492
+ initial sn_effis appended with a set of infos (duration, nsn)
493
+
494
+ """
495
+ # add season length here
496
+ sn_effis = sn_effis.merge(dur_z, left_on=["season", "z"], right_on=["season", "z"])
497
+
498
+ # estimate the number of supernovae
499
+ sn_effis["nsn"] = sn_effis["effi"] * sn_effis["nsn_expected"]
500
+
501
+ return sn_effis
502
+
503
+ def season_info(self, grp, min_duration):
504
+ """
505
+ Method to estimate seasonal info (cadence, season length, ...)
506
+
507
+ Parameters
508
+ --------------
509
+ grp : `pd.DataFrame` group
510
+ min_duration : `float`
511
+ minimal duration for a season to be considered
512
+
513
+ Returns
514
+ ---------
515
+ `pd.DataFrame` with the following cols:
516
+ - Nvisits: number of visits for this group
517
+ - N_xx: number of visits in xx where xx is defined in self.bandstat
518
+
519
+ """
520
+ df = pd.DataFrame([len(grp)], columns=["Nvisits"])
521
+ df["MJD_min"] = grp[self.mjd_col].min()
522
+ df["MJD_max"] = grp[self.mjd_col].max()
523
+ df["season_length"] = df["MJD_max"] - df["MJD_min"]
524
+ df["cadence"] = 0.0
525
+
526
+ if len(grp) > 5:
527
+ # to = grp.groupby(['night'])[self.mjd_col].median().sort_values()
528
+ # df['cadence'] = np.mean(to.diff())
529
+ nights = np.sort(grp["night"].unique())
530
+ diff = np.asarray(nights[1:] - nights[:-1])
531
+ df["cadence"] = np.median(diff).item()
532
+
533
+ # select seasons of at least 30 days
534
+ idx = df["season_length"] >= min_duration
535
+
536
+ return df[idx]
537
+
538
+ def duration_z(self, grp, min_duration=60.0):
539
+ """
540
+ Method to estimate the season length vs redshift
541
+ This is necessary to take into account boundary effects
542
+ when estimating the number of SN that can be detected
543
+
544
+ daymin, daymax = min and max MJD of a season
545
+ T0_min(z) = daymin-(1+z)*min_rf_phase_qual
546
+ T0_max(z) = daymax-(1+z)*max_rf_phase_qual
547
+ season_length(z) = T0_max(z)-T0_min(z)
548
+
549
+ Parameters
550
+ --------------
551
+ grp : `pd.DataFrame` group
552
+ data to process: season infos
553
+ min_duration : `float`, opt
554
+ min season length for a season to be processed (deafult: 60 days)
555
+
556
+ Returns
557
+ ----------
558
+ `pd.DataFrame` with season_length, z, T0_min and T0_max cols
559
+
560
+ """
561
+ # IS THIS CALLED FROM ANYWHERE?
562
+ daymin = grp["MJD_min"].values
563
+ daymax = grp["MJD_max"].values
564
+ dur_z = pd.DataFrame(self.zrange, columns=["z"])
565
+ dur_z["T0_min"] = daymin - (1.0 + dur_z["z"]) * self.min_rf_phase_qual
566
+ dur_z["T0_max"] = daymax - (1.0 + dur_z["z"]) * self.max_rf_phase_qual
567
+ dur_z["season_length"] = dur_z["T0_max"] - dur_z["T0_min"]
568
+ # dur_z['season_length_orig'] = daymax-daymin
569
+ # dur_z['season_length_orig'] = [daymax-daymin]*len(self.zrange)
570
+ nsn = self.nsn_from_rate(dur_z)
571
+ if self.verbose:
572
+ print("dur_z", dur_z)
573
+ print("nsn expected", nsn)
574
+ dur_z = dur_z.merge(nsn, left_on=["z"], right_on=["z"])
575
+
576
+ idx = dur_z["season_length"] > min_duration
577
+ sel = dur_z[idx]
578
+ if len(sel) < 2:
579
+ return pd.DataFrame()
580
+ return dur_z
581
+
582
+ def calc_daymax(self, grp, daymax_step):
583
+ """
584
+ Method to estimate T0 (daymax) values for simulation.
585
+
586
+ Parameters
587
+ --------------
588
+ grp: group (`pd.DataFrame` sense)
589
+ group of data to process with the following cols:
590
+ t0_min: T0 min value (per season)
591
+ t0_max: T0 max value (per season)
592
+ daymax_step: `float`
593
+ step for T0 simulation
594
+
595
+ Returns
596
+ ----------
597
+ `pd.DataFrame` with daymax, min_rf_phase, max_rf_phase values
598
+
599
+ """
600
+
601
+ if self.t0s == "all":
602
+ t0_max = grp["T0_max"].values
603
+ t0_min = grp["T0_min"].values
604
+ num = (t0_max - t0_min) / daymax_step
605
+ if t0_max - t0_min > 10:
606
+ df = pd.DataFrame(np.linspace(t0_min, t0_max, int(np.max(num))), columns=["daymax"])
607
+ else:
608
+ df = pd.DataFrame([-1], columns=["daymax"])
609
+ else:
610
+ df = pd.DataFrame([0.0], columns=["daymax"])
611
+
612
+ df["minRFphase"] = self.min_rf_phase
613
+ df["maxRFphase"] = self.max_rf_phase
614
+
615
+ return df
616
+
617
+ def gen_lc(self, grp, gen_par_orig, x1, color):
618
+ """
619
+ Method to generate light curves from observations
620
+
621
+ Parameters
622
+ ---------------
623
+ grp : pd group
624
+ observations to process
625
+ gen_par_orig : `pd.DataFrame`
626
+ simulation parameters
627
+ x1 : `float`
628
+ SN stretch
629
+ color : `float`
630
+ SN color
631
+
632
+ Returns
633
+ ----------
634
+ light curves as `pd.DataFrame`
635
+
636
+ """
637
+ season = grp.name
638
+ idx = gen_par_orig["season"] == season
639
+ gen_par = gen_par_orig[idx].to_records(index=False)
640
+
641
+ sntype = dict(zip([(-2.0, 0.2), (0.0, 0.0)], ["faint", "medium"]))
642
+ res = pd.DataFrame()
643
+ key = (np.round(x1, 1), np.round(color, 1))
644
+ vals = self.lc_fast[key]
645
+
646
+ gen_par_cp = gen_par.copy()
647
+ if key == (-2.0, 0.2):
648
+ idx = gen_par_cp["z"] < 0.9
649
+ gen_par_cp = gen_par_cp[idx]
650
+ lc = vals(grp.to_records(index=False), 0.0, gen_par_cp, bands="grizy")
651
+ lc["x1"] = key[0]
652
+ lc["color"] = key[1]
653
+ lc["sntype"] = sntype[key]
654
+ res = pd.concat((res, lc))
655
+
656
+ return res
657
+
658
+ def sn_effi(self, lc):
659
+ """
660
+ Method to transform LCs to supernovae
661
+
662
+ Parameters
663
+ ---------------
664
+ lc : pd grp
665
+ light curve
666
+
667
+ Returns
668
+ ----------
669
+ `pd.DataFrame` of sn efficiencies vs z
670
+ """
671
+
672
+ if self.verbose:
673
+ print("effi for", lc.name)
674
+
675
+ lcarr = lc.to_records(index=False)
676
+
677
+ idx = lcarr["snr_m5"] >= self.snr_min
678
+
679
+ lcarr = np.copy(lcarr[idx])
680
+
681
+ t0s = np.unique(lcarr["daymax"])
682
+ t0s.sort()
683
+
684
+ delta_t = lcarr["daymax"] - t0s[:, np.newaxis]
685
+
686
+ flag = np.abs(delta_t) < 1.0e-5
687
+
688
+ resdf = pd.DataFrame(t0s, columns=["daymax"])
689
+
690
+ # get n_phase_min, n_phase_max
691
+ for vv in [
692
+ "n_phmin",
693
+ "n_phmax",
694
+ "F_x0x0",
695
+ "F_x0x1",
696
+ "F_x0daymax",
697
+ "F_x0color",
698
+ "F_x1x1",
699
+ "F_x1daymax",
700
+ "F_x1color",
701
+ "F_daymaxdaymax",
702
+ "F_daymaxcolor",
703
+ "F_colorcolor",
704
+ ]:
705
+ resdf[vv] = self.get_sum(lcarr, vv, len(delta_t), flag)
706
+
707
+ nights = np.tile(lcarr["night"], (len(delta_t), 1))
708
+ phases = np.tile(lcarr["phase"], (len(delta_t), 1))
709
+
710
+ flagph = phases >= 0.0
711
+ resdf["nepochs_aft"] = self.get_epochs(nights, flag, flagph)
712
+ flagph = phases <= 0.0
713
+ resdf["nepochs_bef"] = self.get_epochs(nights, flag, flagph)
714
+
715
+ # replace NaN by 0
716
+ # solution from: https://stackoverflow.com/
717
+ # questions/77900971/
718
+ # pandas-futurewarning-downcasting-
719
+ # object-dtype-arrays-on-fillna-ffill-bfill
720
+ with pd.option_context("future.no_silent_downcasting", True):
721
+ resdf = resdf.fillna(0).infer_objects(copy=False)
722
+
723
+ # get selection efficiencies
724
+ effis = self.efficiencies(resdf)
725
+
726
+ return effis
727
+
728
+ def get_sum(self, lcarr, varname, nvals, flag):
729
+ """
730
+ Method to get the sum of variables using broadcasting
731
+
732
+ Parameters
733
+ --------------
734
+ lcarr : numpy array
735
+ data to process
736
+ varname : `str`
737
+ col to process in lcarr
738
+ nvals : `int`
739
+ dimension for tiling
740
+ flag : array(bool)
741
+ flag to apply
742
+
743
+ Returns
744
+ ----------
745
+ array: the sum of the corresponding variable
746
+
747
+ """
748
+
749
+ phmin = np.tile(lcarr[varname], (nvals, 1))
750
+ n_phmin = np.ma.array(phmin, mask=~flag)
751
+ n_phmin = n_phmin.sum(axis=1)
752
+
753
+ return n_phmin
754
+
755
+ def get_epochs(self, nights, flag, flagph):
756
+ """
757
+ Method to get the number of epochs
758
+
759
+ Parameters
760
+ ---------------
761
+ nights : array
762
+ night number array
763
+ flag : array(bool)
764
+ flag to apply
765
+ flagph : array(bool)
766
+ flag to apply
767
+
768
+ Returns
769
+ -----------
770
+ array with the number of epochs
771
+
772
+ """
773
+ nights_cp = np.copy(nights)
774
+ B = np.ma.array(nights_cp, mask=~(flag & flagph))
775
+ B.sort(axis=1)
776
+ C = np.diff(B, axis=1) > 0
777
+ D = C.sum(axis=1) + 1
778
+ return D
779
+
780
+ def sigma_s_nparams(self, grp):
781
+ """
782
+ Method to estimate variances of SN parameters
783
+ from inversion of the Fisher matrix
784
+
785
+ Parameters
786
+ ---------------
787
+ grp: `pd.DataFrame` of flux derivatives wrt SN parameters
788
+ Returns
789
+ ----------
790
+ Diagonal elements of the inverted matrix (as `pd.DataFrame`)
791
+ """
792
+
793
+ # params = ['x0', 'x1', 'daymax', 'color']
794
+ parts = {}
795
+ for ia, vala in enumerate(self.params):
796
+ for jb, valb in enumerate(self.params):
797
+ if jb >= ia:
798
+ parts[ia, jb] = grp["F_" + vala + valb]
799
+
800
+ # print(parts)
801
+ size = len(grp)
802
+ npar = len(self.params)
803
+ fisher__big = np.zeros((npar * size, npar * size))
804
+ big__diag = np.zeros((npar * size, npar * size))
805
+ big__diag = []
806
+
807
+ for iv in range(size):
808
+ for ia, vala in enumerate(self.params):
809
+ for jb, valb in enumerate(self.params):
810
+ if jb >= ia:
811
+ fisher__big[ia + npar * iv][jb + npar * iv] = parts[ia, jb][iv]
812
+
813
+ # pprint.pprint(fisher__big)
814
+
815
+ fisher__big = fisher__big + np.triu(fisher__big, 1).T
816
+ big__diag = np.diag(np.linalg.inv(fisher__big))
817
+
818
+ res = pd.DataFrame()
819
+ for ia, vala in enumerate(self.params):
820
+ indices = range(ia, len(big__diag), npar)
821
+ res["Cov_{}{}".format(vala, vala)] = np.take(big__diag, indices)
822
+
823
+ return res
824
+
825
+ def efficiencies(self, dfo):
826
+ """ "
827
+ Method to estimate selection efficiencies
828
+
829
+ Parameters
830
+ ---------------
831
+ df: `pd.DataFrame`
832
+ data to process
833
+
834
+ """
835
+
836
+ if self.verbose:
837
+ print(
838
+ "selection params",
839
+ self.n_phase_min,
840
+ self.n_phase_max,
841
+ self.n_bef,
842
+ self.n_aft,
843
+ )
844
+ print(dfo)
845
+ df = pd.DataFrame(dfo)
846
+ df["select"] = df["n_phmin"] >= self.n_phase_min
847
+ df["select"] &= df["n_phmax"] >= self.n_phase_max
848
+ df["select"] &= df["nepochs_bef"] >= self.n_bef
849
+ df["select"] &= df["nepochs_aft"] >= self.n_aft
850
+ df["select"] = df["select"].astype(int)
851
+ df["Cov_colorcolor"] = 100.0
852
+
853
+ idx = df["select"] == 1
854
+
855
+ bad_sn = pd.DataFrame(df.loc[~idx])
856
+ good_sn = pd.DataFrame()
857
+ if len(df[idx]) > 0:
858
+ good_sn = pd.DataFrame(df.loc[idx].reset_index())
859
+ sigma__fisher = self.sigma_s_nparams(good_sn)
860
+ good_sn["Cov_colorcolor"] = sigma__fisher["Cov_colorcolor"]
861
+
862
+ all_sn = pd.concat((good_sn, bad_sn))
863
+ all_sn["select"] &= all_sn["Cov_colorcolor"] <= self.sigma_c**2
864
+ idx = all_sn["select"] == 1
865
+
866
+ if self.verbose:
867
+ if len(good_sn) > 0:
868
+ print("good SN", len(good_sn), good_sn[["daymax", "Cov_colorcolor"]])
869
+ else:
870
+ print("no good SN")
871
+ return pd.DataFrame({"ntot": [len(all_sn)], "nsel": [len(all_sn[idx])]})
872
+
873
+ def metric(self, data_slice, zseason, x1=-2.0, color=0.2, zlim=-1, metric="zlim"):
874
+ """
875
+ Method to run the metric
876
+
877
+ Parameters
878
+ ---------------
879
+ data_slice: array
880
+ observations to use for processing
881
+ zseason: array
882
+ season infos (season length vs z)
883
+ x1: float, opt
884
+ SN stretch (default: -2.0)
885
+ color: float, opt
886
+ SN color (default: -0.2)
887
+ zlim: float, opt
888
+ redshift limit used to estimate NSN (default: -1)
889
+ metric: str, opt
890
+ metric to estimate [zlim or nsn] (default: zlim)
891
+
892
+
893
+ """
894
+ """
895
+ snType = "medium"
896
+ if np.abs(x1 + 2.0) <= 1.0e-5:
897
+ snType = "faint"
898
+ """
899
+
900
+ # get the season durations
901
+ seasons, dur_z = self.season_length(self.season, data_slice, zseason)
902
+ if not seasons or dur_z.empty:
903
+ return None
904
+
905
+ # chek the redshift range per season
906
+ dur_z = self.check_dur_z(dur_z)
907
+ if dur_z.empty:
908
+ return None
909
+
910
+ # Stick a season column on in case it got killed by a groupby
911
+ if "season" not in list(dur_z.columns):
912
+ dur_z["season"] = dur_z["index"] * 0 + np.unique(seasons)
913
+
914
+ # get simulation parameters
915
+ if np.size(np.unique(seasons)) > 1:
916
+ dur_z["z_copy"] = dur_z["z"].values.copy()
917
+ dur_z["season_copy"] = dur_z["season"].values.copy()
918
+ gen_par = (
919
+ dur_z.groupby(["z", "season"])
920
+ .apply(lambda x: self.calc_daymax(x, self.daymax_step), include_groups=False)
921
+ .reset_index()
922
+ )
923
+ else:
924
+ dur_z["z_copy"] = dur_z["z"].values.copy()
925
+ gen_par = (
926
+ dur_z.groupby(["z"])
927
+ .apply(lambda x: self.calc_daymax(x, self.daymax_step), include_groups=False)
928
+ .reset_index()
929
+ )
930
+ gen_par["season"] = gen_par["level_1"] * 0 + np.unique(seasons)
931
+
932
+ if gen_par.empty:
933
+ return None
934
+
935
+ # select observations corresponding to seasons
936
+ obs = pd.DataFrame(np.copy(data_slice))
937
+ obs = obs[obs["season"].isin(seasons)]
938
+
939
+ # metric values in a DataFrame
940
+ metric_values = pd.DataFrame()
941
+
942
+ # generate LC here
943
+ lc = self.step_lc(obs, gen_par, x1=x1, color=color)
944
+
945
+ if self.verbose:
946
+ print("daymax values", lc["daymax"].unique(), len(lc["daymax"].unique()))
947
+ print(
948
+ lc[
949
+ [
950
+ "daymax",
951
+ "z",
952
+ "flux",
953
+ "fluxerr_photo",
954
+ "flux_e_sec",
955
+ "flux_5",
956
+ self.m5_col,
957
+ ]
958
+ ]
959
+ )
960
+
961
+ if len(lc) == 0:
962
+ return None
963
+
964
+ # get observing efficiencies and build sn for metric
965
+ lc.index = lc.index.droplevel()
966
+
967
+ # estimate efficiencies
968
+ sn_effis = self.step_efficiencies(lc)
969
+
970
+ # estimate nsn
971
+ sn = self.step_nsn(sn_effis, dur_z)
972
+
973
+ # estimate redshift completeness
974
+ if metric == "zlim":
975
+ sn["season_copy"] = sn["season"].values.copy()
976
+ metric_values = (
977
+ sn.groupby(["season"]).apply(lambda x: self.zlim(x), include_groups=False).reset_index()
978
+ )
979
+
980
+ if metric == "nsn":
981
+ sn = sn.merge(zlim, left_on=["season"], right_on=["season"])
982
+ sn["season_copy"] = sn["season"].values.copy()
983
+ metric_values = (
984
+ sn.groupby(["season"]).apply(lambda x: self.nsn(x), include_groups=False).reset_index()
985
+ )
986
+
987
+ return metric_values
988
+
989
+ def z_season(self, seasons, data_slice):
990
+ """
991
+ Fill the z values per season
992
+
993
+ Parameters
994
+ --------------
995
+ seasons: list
996
+ seasons to process
997
+ data_slice: array
998
+ data to process
999
+
1000
+ """
1001
+ # if seasons = -1: process the seasons seen in data
1002
+ if seasons == [-1]:
1003
+ seasons = np.unique(data_slice[self.season_col])
1004
+
1005
+ # `pd.DataFrame` with zmin, zmax, zstep per season
1006
+ zseason = pd.DataFrame(seasons, columns=["season"])
1007
+ zseason["zmin"] = self.zmin
1008
+ zseason["zmax"] = self.zmax
1009
+ zseason["zstep"] = self.zstep
1010
+
1011
+ return zseason
1012
+
1013
+ def z_season_allz(self, zseason):
1014
+
1015
+ zseason["season_copy"] = zseason["season"].values.copy()
1016
+ zseason_allz = (
1017
+ zseason.groupby(["season"])
1018
+ .apply(
1019
+ lambda x: pd.DataFrame(
1020
+ {"z": list(np.arange(x["zmin"].mean(), x["zmax"].mean(), x["zstep"].mean()))}
1021
+ ),
1022
+ include_groups=False,
1023
+ )
1024
+ .reset_index()
1025
+ )
1026
+
1027
+ return zseason_allz[["season", "z"]]
1028
+
1029
+ def nsn_from_rate(self, grp):
1030
+ """
1031
+ Method to estimate the expected number of supernovae
1032
+
1033
+ Parameters
1034
+ ---------------
1035
+ grp: `pd.DataFrame`
1036
+ data to process
1037
+
1038
+ Returns
1039
+ -----------
1040
+ `pd.DataFrame` with z and nsn_expected as cols
1041
+
1042
+ """
1043
+ durinterp_z = interp1d(
1044
+ grp["z"],
1045
+ grp["season_length"],
1046
+ kind="linear",
1047
+ bounds_error=False,
1048
+ fill_value=0,
1049
+ )
1050
+ zz, rate, err_rate, nsn, err_nsn = self.rate_sn(
1051
+ zmin=self.zmin,
1052
+ zmax=self.zmax,
1053
+ dz=self.zstep,
1054
+ duration_z=durinterp_z,
1055
+ # duration=self.duration_ref,
1056
+ survey_area=self.pix_area,
1057
+ account_for_edges=False,
1058
+ )
1059
+
1060
+ nsn_expected = interp1d(zz, nsn, kind="linear", bounds_error=False, fill_value=0)
1061
+ nsn_res = nsn_expected(grp["z"])
1062
+
1063
+ return pd.DataFrame({"nsn_expected": nsn_res, "z": grp["z"].to_list()})
1064
+
1065
+ def coadd(self, obs):
1066
+ """
1067
+ Method to coadd data per band and per night
1068
+
1069
+ Parameters
1070
+ ------------
1071
+ data : `pd.DataFrame`
1072
+ `pd.DataFrame` of observations
1073
+
1074
+ Returns
1075
+ -------
1076
+ coadded data : `pd.DataFrame`
1077
+
1078
+ """
1079
+
1080
+ data = pd.DataFrame(np.copy(obs))
1081
+ keygroup = [self.filter_col, self.night_col]
1082
+
1083
+ data.sort_values(by=keygroup, ascending=[True, True], inplace=True)
1084
+
1085
+ # get the median single exptime
1086
+ exptime_single = data[self.exptime_col].median()
1087
+ coadd_df = (
1088
+ data.groupby(keygroup)
1089
+ .agg(
1090
+ {
1091
+ self.nexp_col: ["sum"],
1092
+ self.vistime_col: ["sum"],
1093
+ self.exptime_col: ["sum"],
1094
+ self.mjd_col: ["mean"],
1095
+ self.m5_col: ["mean"],
1096
+ }
1097
+ )
1098
+ .reset_index()
1099
+ )
1100
+
1101
+ coadd_df.columns = [
1102
+ self.filter_col,
1103
+ self.night_col,
1104
+ self.nexp_col,
1105
+ self.vistime_col,
1106
+ self.exptime_col,
1107
+ self.mjd_col,
1108
+ self.m5_col,
1109
+ ]
1110
+
1111
+ coadd_df = coadd_df.sort_values(by=self.mjd_col)
1112
+ coadd_df[self.m5_col] += 1.25 * np.log10(coadd_df[self.exptime_col] / exptime_single)
1113
+
1114
+ return coadd_df.to_records(index=False)
1115
+
1116
+ def getseason(self, obs, season_gap=80.0, mjd_col="observationStartMJD"):
1117
+ """
1118
+ Method to estimate seasons
1119
+
1120
+ Parameters
1121
+ ------------
1122
+ obs: `np.ndarray`
1123
+ array of observations
1124
+ season_gap: `float`, optional
1125
+ minimal gap required to define a season (default: 80 days)
1126
+ mjd_col: `str`, optional
1127
+ col name for MJD infos (default: observationStartMJD)
1128
+
1129
+ Returns
1130
+ ---------
1131
+ obs : `np.ndarray`
1132
+ original numpy array with seasonnumber appended
1133
+ """
1134
+
1135
+ # check whether season has already been estimated
1136
+ obs.sort(order=mjd_col)
1137
+
1138
+ seasoncalc = np.ones(obs.size, dtype=int)
1139
+
1140
+ if len(obs) > 1:
1141
+ diff = np.diff(obs[mjd_col])
1142
+ flag = np.where(diff > season_gap)[0]
1143
+
1144
+ if len(flag) > 0:
1145
+ for i, indx in enumerate(flag):
1146
+ seasoncalc[indx + 1 :] = i + 2
1147
+
1148
+ obs = nlr.append_fields(obs, "season", seasoncalc)
1149
+
1150
+ return obs
1151
+
1152
+ def reducen_sn(self, metric_val):
1153
+ # At each slice_point, return the sum nSN value.
1154
+
1155
+ return np.sum(metric_val["n_sn"])
1156
+
1157
+ def reducezlim(self, metric_val):
1158
+ # At each slice_point, return the median zlim
1159
+ result = np.median(metric_val["zlim"])
1160
+ if result < 0:
1161
+ result = self.badval
1162
+
1163
+ return result
1164
+
1165
+ def nsn_expected_z(self, grp):
1166
+ """
1167
+ Method to estimate the expected nsn vs redshift
1168
+
1169
+ Parameters
1170
+ --------------
1171
+ grp: `pd.DataFrame` group
1172
+ data to process: season infos
1173
+
1174
+ Returns
1175
+ ----------
1176
+ `pd.DataFrame` with season_length, z, nsn_expected cols
1177
+
1178
+ """
1179
+
1180
+ if len(grp) < 2:
1181
+ nsn = pd.DataFrame(grp["z"].to_list(), columns=["z"])
1182
+ nsn.loc[:, "nsn_expected"] = 0
1183
+ else:
1184
+ nsn = self.nsn_from_rate(grp)
1185
+
1186
+ if self.verbose:
1187
+ print("dur_z", grp)
1188
+ print("nsn expected", nsn)
1189
+
1190
+ dur_z = pd.DataFrame(grp)
1191
+ dur_z = dur_z.merge(nsn, left_on=["z"], right_on=["z"])
1192
+
1193
+ # if "season" in dur_z.columns:
1194
+ # dur_z = dur_z.drop(columns=["season"])
1195
+
1196
+ return dur_z
1197
+
1198
+ def zlim_or_nsn(self, effi, sntype="faint", zlim=-1.0):
1199
+ """
1200
+ Method to estimate the redshift limit or the number of sn
1201
+
1202
+ Parameters
1203
+ ---------------
1204
+ effi : `pd.DataFrame`
1205
+ data to process
1206
+ sntype : `str`, opt
1207
+ type of SN to consider for estimation (default: faint)
1208
+ zlim : `float`, opt
1209
+ redshift limit
1210
+
1211
+ Returns
1212
+ -----------
1213
+ if zlim<0: returns the redshift limit
1214
+ if zlim>0: returns the number of sn up to zlim
1215
+
1216
+
1217
+ """
1218
+
1219
+ seleffi = effi[effi["sntype"] == sntype]
1220
+ seleffi = seleffi.reset_index(drop=True)
1221
+ seleffi = seleffi.sort_values(by=["z"])
1222
+ nsn_cum = np.cumsum(seleffi["nsn"].to_list())
1223
+
1224
+ resa = -1.0
1225
+ if zlim < 0:
1226
+ df = pd.DataFrame(seleffi).reset_index(drop=True)
1227
+ df.loc[:, "nsn_cum"] = nsn_cum / nsn_cum[-1]
1228
+ index = df[df["nsn_cum"] < 1].index
1229
+ if len(index) == 0:
1230
+ return resa
1231
+ dfb = df[: index[-1] + 2]
1232
+ zlim = interp1d(
1233
+ dfb["nsn_cum"],
1234
+ dfb["z"],
1235
+ kind="linear",
1236
+ bounds_error=False,
1237
+ fill_value=0,
1238
+ )
1239
+ resa = zlim(self.zlim_coeff)
1240
+ else:
1241
+ effi = interp1d(
1242
+ seleffi["z"],
1243
+ seleffi["effi"],
1244
+ kind="linear",
1245
+ bounds_error=False,
1246
+ fill_value=0,
1247
+ )
1248
+ durinterp_z = interp1d(
1249
+ seleffi["z"],
1250
+ seleffi["season_length"],
1251
+ kind="linear",
1252
+ bounds_error=False,
1253
+ fill_value=0,
1254
+ )
1255
+ zmin, zstep = 0.1, 0.001
1256
+ resa = self.get_nsn(effi, durinterp_z, zmin, zlim, zstep)
1257
+
1258
+ return np.round(resa, 6)
1259
+
1260
+ def zlim(self, grp, sn_type="faint"):
1261
+ """
1262
+ Method to estimate the metric zcomp
1263
+
1264
+ Parameters
1265
+ ---------------
1266
+ grp: pd group
1267
+ sn_type: str, opt
1268
+ type of SN to estimate zlim (default: faint)
1269
+
1270
+ Returns
1271
+ ------------
1272
+ zcomp : `pd.DataFrame` with the metric as cols
1273
+ """
1274
+ zcomp = -1
1275
+
1276
+ if grp["effi"].mean() > 0.02 and len(grp["effi"]) >= 2:
1277
+ zcomp = self.zlim_or_nsn(grp, sn_type, -1)
1278
+
1279
+ return pd.DataFrame({"zcomp": [zcomp]})
1280
+
1281
+ def nsn(self, grp, sn_type="medium"):
1282
+ """
1283
+ Method to estimate the metric nsn up to zlim
1284
+
1285
+ Parameters
1286
+ ---------------
1287
+ grp: pd group
1288
+ sn_type: str, opt
1289
+ type of SN to estimate zlim (default: medium)
1290
+
1291
+ Returns
1292
+ ------------
1293
+ nsn : `pd.DataFrame`
1294
+ Dataframe with the metric as cols
1295
+ """
1296
+ nsn = -1
1297
+
1298
+ if grp["effi"].mean() > 0.02:
1299
+ nsn = self.zlim_or_nsn(grp, sn_type, grp["zcomp"].mean())
1300
+
1301
+ return pd.DataFrame({"nsn": [nsn]})
1302
+
1303
+ def get_nsn(self, effi, durinterp_z, zmin, zmax, zstep):
1304
+ """
1305
+ Method to estimate to total number of SN: NSN = Sum(effi(z)*rate(z))
1306
+
1307
+ Parameters
1308
+ -----------
1309
+ effi : 1D interpolator
1310
+ efficiencies vs z
1311
+ durinterp_z : 1D interpolator
1312
+ duration vs z
1313
+ zmin : `float`
1314
+ redshift min
1315
+ zmax : `float`
1316
+ redshift max
1317
+ zstep : `float`
1318
+ redshift step
1319
+
1320
+ Returns
1321
+ ----------
1322
+ tot_sn : `int`
1323
+ total number of SN up to zmax
1324
+ """
1325
+
1326
+ zz, rate, err_rate, nsn, err_nsn = self.rate_sn(
1327
+ zmin=zmin,
1328
+ zmax=zmax + zstep,
1329
+ dz=zstep,
1330
+ duration_z=durinterp_z,
1331
+ # duration=180.,
1332
+ survey_area=self.pix_area,
1333
+ account_for_edges=False,
1334
+ )
1335
+ res = np.cumsum(effi(zz) * nsn)
1336
+ if np.size(res) > 0:
1337
+ return res[-1]
1338
+ else:
1339
+ return 0
1340
+
1341
+ def check_dur_z(self, dur_z, nmin=2):
1342
+ """ "
1343
+ Method to remove seasons with a poor redshift range due
1344
+ to too low season length
1345
+
1346
+ Parameters
1347
+ ----------------
1348
+ dur_z: `pd.DataFrame`
1349
+ data to process
1350
+ nmin: int, opt
1351
+ minimal number of redshift points per season (default: 2)
1352
+
1353
+ Returns
1354
+ -----------
1355
+ dur_z_subset : `pd.DataFrame`
1356
+ dur_z but only with seasons having at least nmin points in redshift
1357
+
1358
+ """
1359
+
1360
+ dur_z["size"] = dur_z.groupby(["season"])["z"].transform("size")
1361
+
1362
+ idx = dur_z["size"] >= nmin
1363
+
1364
+ return pd.DataFrame(dur_z[idx])