lalsuite 7.26.2.dev20251218__cp314-cp314t-manylinux_2_28_x86_64.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 (733) hide show
  1. lal/__init__.py +145 -0
  2. lal/_lal.cpython-314t-x86_64-linux-gnu.so +0 -0
  3. lal/_lal_swig.py +12 -0
  4. lal/antenna.py +1200 -0
  5. lal/git_version.py +64 -0
  6. lal/gpstime.py +233 -0
  7. lal/iterutils.py +408 -0
  8. lal/pipeline.py +3139 -0
  9. lal/rate.py +2455 -0
  10. lal/series.py +244 -0
  11. lal/utils/__init__.py +29 -0
  12. lal/utils/cache.py +379 -0
  13. lal/utils/series.py +277 -0
  14. lalapps/__init__.py +26 -0
  15. lalapps/bin/lal_cache +0 -0
  16. lalapps/bin/lal_fftw_wisdom +0 -0
  17. lalapps/bin/lal_fftwf_wisdom +0 -0
  18. lalapps/bin/lal_simd_detect +0 -0
  19. lalapps/bin/lal_tconvert +0 -0
  20. lalapps/bin/lal_version +0 -0
  21. lalapps/bin/lalapps_ComputeAntennaPattern +16 -0
  22. lalapps/bin/lalapps_ComputeFstatBenchmark +16 -0
  23. lalapps/bin/lalapps_ComputeFstatLatticeCount +16 -0
  24. lalapps/bin/lalapps_ComputeFstatMCUpperLimit +16 -0
  25. lalapps/bin/lalapps_ComputeFstatistic_v2 +16 -0
  26. lalapps/bin/lalapps_ComputePSD +16 -0
  27. lalapps/bin/lalapps_CopySFTs +16 -0
  28. lalapps/bin/lalapps_DistanceVsMass +0 -0
  29. lalapps/bin/lalapps_DriveHoughMulti +16 -0
  30. lalapps/bin/lalapps_FstatMetric_v2 +16 -0
  31. lalapps/bin/lalapps_HierarchSearchGCT +16 -0
  32. lalapps/bin/lalapps_HierarchicalSearch +16 -0
  33. lalapps/bin/lalapps_MakeSFTDAG +16 -0
  34. lalapps/bin/lalapps_MakeSFTs +16 -0
  35. lalapps/bin/lalapps_Makefakedata_v4 +16 -0
  36. lalapps/bin/lalapps_Makefakedata_v5 +16 -0
  37. lalapps/bin/lalapps_PredictFstat +16 -0
  38. lalapps/bin/lalapps_PrintDetectorState +16 -0
  39. lalapps/bin/lalapps_SFTclean +16 -0
  40. lalapps/bin/lalapps_SFTvalidate +16 -0
  41. lalapps/bin/lalapps_StringAddFrame +0 -0
  42. lalapps/bin/lalapps_StringSearch +0 -0
  43. lalapps/bin/lalapps_Weave +16 -0
  44. lalapps/bin/lalapps_WeaveCompare +16 -0
  45. lalapps/bin/lalapps_WeaveConcat +16 -0
  46. lalapps/bin/lalapps_WeaveSetup +16 -0
  47. lalapps/bin/lalapps_WriteSFTsfromSFDBs +16 -0
  48. lalapps/bin/lalapps_animate +0 -0
  49. lalapps/bin/lalapps_binj +0 -0
  50. lalapps/bin/lalapps_blindinj +0 -0
  51. lalapps/bin/lalapps_cache +16 -0
  52. lalapps/bin/lalapps_calfacs +0 -0
  53. lalapps/bin/lalapps_cbc_stochasticbank +0 -0
  54. lalapps/bin/lalapps_chirplen +0 -0
  55. lalapps/bin/lalapps_coh_PTF_inspiral +0 -0
  56. lalapps/bin/lalapps_coinj +0 -0
  57. lalapps/bin/lalapps_combine_crosscorr_toplists +16 -0
  58. lalapps/bin/lalapps_compareFstats +16 -0
  59. lalapps/bin/lalapps_compareSFTs +16 -0
  60. lalapps/bin/lalapps_create_time_correction_ephemeris +16 -0
  61. lalapps/bin/lalapps_dumpSFT +16 -0
  62. lalapps/bin/lalapps_effdist +0 -0
  63. lalapps/bin/lalapps_exc_resp +0 -0
  64. lalapps/bin/lalapps_fftw_wisdom +16 -0
  65. lalapps/bin/lalapps_fftwf_wisdom +16 -0
  66. lalapps/bin/lalapps_fits_header_getval +16 -0
  67. lalapps/bin/lalapps_fits_header_list +16 -0
  68. lalapps/bin/lalapps_fits_overview +16 -0
  69. lalapps/bin/lalapps_fits_table_list +16 -0
  70. lalapps/bin/lalapps_fr_ninja +0 -0
  71. lalapps/bin/lalapps_frextr +0 -0
  72. lalapps/bin/lalapps_frinfo +0 -0
  73. lalapps/bin/lalapps_frjoin +0 -0
  74. lalapps/bin/lalapps_frread +0 -0
  75. lalapps/bin/lalapps_frview +0 -0
  76. lalapps/bin/lalapps_gwf2xml +0 -0
  77. lalapps/bin/lalapps_heterodyne_pulsar +16 -0
  78. lalapps/bin/lalapps_inspawgfile +0 -0
  79. lalapps/bin/lalapps_inspfrinj +0 -0
  80. lalapps/bin/lalapps_inspinj +0 -0
  81. lalapps/bin/lalapps_inspiralDistance +0 -0
  82. lalapps/bin/lalapps_knope +16 -0
  83. lalapps/bin/lalapps_knope_automation_script +16 -0
  84. lalapps/bin/lalapps_knope_collate_results +16 -0
  85. lalapps/bin/lalapps_knope_result_page +16 -0
  86. lalapps/bin/lalapps_makeblindinj +85 -0
  87. lalapps/bin/lalapps_makeblindinj_himass +67 -0
  88. lalapps/bin/lalapps_ninja +0 -0
  89. lalapps/bin/lalapps_path2cache +16 -0
  90. lalapps/bin/lalapps_power +0 -0
  91. lalapps/bin/lalapps_pulsar_crosscorr_v2 +16 -0
  92. lalapps/bin/lalapps_pulsar_frequency_evolution +16 -0
  93. lalapps/bin/lalapps_pulsar_parameter_estimation_nested +16 -0
  94. lalapps/bin/lalapps_random_bank +0 -0
  95. lalapps/bin/lalapps_randombank +0 -0
  96. lalapps/bin/lalapps_run_pulsar_crosscorr_v2 +16 -0
  97. lalapps/bin/lalapps_searchsum2cache +16 -0
  98. lalapps/bin/lalapps_spec_avg +16 -0
  99. lalapps/bin/lalapps_spec_avg_long +16 -0
  100. lalapps/bin/lalapps_spec_coherence +16 -0
  101. lalapps/bin/lalapps_spininj +0 -0
  102. lalapps/bin/lalapps_splitSFTs +16 -0
  103. lalapps/bin/lalapps_splitbank +0 -0
  104. lalapps/bin/lalapps_ssbtodetector +16 -0
  105. lalapps/bin/lalapps_synthesizeBstatMC +16 -0
  106. lalapps/bin/lalapps_synthesizeLVStats +16 -0
  107. lalapps/bin/lalapps_synthesizeTransientStats +16 -0
  108. lalapps/bin/lalapps_tconvert +16 -0
  109. lalapps/bin/lalapps_tmpltbank +0 -0
  110. lalapps/bin/lalapps_version +0 -0
  111. lalapps/bin/lalapps_xtefitstoframe +0 -0
  112. lalapps/bin/lalburst_version +0 -0
  113. lalapps/bin/lalfr-cat +0 -0
  114. lalapps/bin/lalfr-cksum +0 -0
  115. lalapps/bin/lalfr-cut +0 -0
  116. lalapps/bin/lalfr-dump +0 -0
  117. lalapps/bin/lalfr-fmt +0 -0
  118. lalapps/bin/lalfr-paste +0 -0
  119. lalapps/bin/lalfr-print +0 -0
  120. lalapps/bin/lalfr-split +0 -0
  121. lalapps/bin/lalfr-stat +0 -0
  122. lalapps/bin/lalfr-stream +0 -0
  123. lalapps/bin/lalfr-vis +0 -0
  124. lalapps/bin/lalframe_version +0 -0
  125. lalapps/bin/lalinference_bench +0 -0
  126. lalapps/bin/lalinference_burst +0 -0
  127. lalapps/bin/lalinference_datadump +0 -0
  128. lalapps/bin/lalinference_injectedlike +0 -0
  129. lalapps/bin/lalinference_mpi_wrapper +59 -0
  130. lalapps/bin/lalinference_nest +0 -0
  131. lalapps/bin/lalinference_version +0 -0
  132. lalapps/bin/lalinspiral_version +0 -0
  133. lalapps/bin/lalmetaio_version +0 -0
  134. lalapps/bin/lalpulsar_ComputeAntennaPattern +0 -0
  135. lalapps/bin/lalpulsar_ComputeFstatBenchmark +0 -0
  136. lalapps/bin/lalpulsar_ComputeFstatLatticeCount +0 -0
  137. lalapps/bin/lalpulsar_ComputeFstatMCUpperLimit +0 -0
  138. lalapps/bin/lalpulsar_ComputeFstatistic_v2 +0 -0
  139. lalapps/bin/lalpulsar_ComputePSD +0 -0
  140. lalapps/bin/lalpulsar_DriveHoughMulti +0 -0
  141. lalapps/bin/lalpulsar_FstatMetric_v2 +0 -0
  142. lalapps/bin/lalpulsar_HierarchSearchGCT +0 -0
  143. lalapps/bin/lalpulsar_HierarchicalSearch +0 -0
  144. lalapps/bin/lalpulsar_MakeSFTs +0 -0
  145. lalapps/bin/lalpulsar_Makefakedata_v4 +0 -0
  146. lalapps/bin/lalpulsar_Makefakedata_v5 +0 -0
  147. lalapps/bin/lalpulsar_PredictFstat +0 -0
  148. lalapps/bin/lalpulsar_PrintDetectorState +0 -0
  149. lalapps/bin/lalpulsar_SFTclean +0 -0
  150. lalapps/bin/lalpulsar_SFTvalidate +0 -0
  151. lalapps/bin/lalpulsar_Weave +0 -0
  152. lalapps/bin/lalpulsar_WeaveCompare +0 -0
  153. lalapps/bin/lalpulsar_WeaveConcat +0 -0
  154. lalapps/bin/lalpulsar_WeaveSetup +0 -0
  155. lalapps/bin/lalpulsar_WriteSFTsfromSFDBs +0 -0
  156. lalapps/bin/lalpulsar_compareFstats +0 -0
  157. lalapps/bin/lalpulsar_compareSFTs +0 -0
  158. lalapps/bin/lalpulsar_create_time_correction_ephemeris +0 -0
  159. lalapps/bin/lalpulsar_crosscorr_v2 +0 -0
  160. lalapps/bin/lalpulsar_dumpSFT +0 -0
  161. lalapps/bin/lalpulsar_fits_header_getval +0 -0
  162. lalapps/bin/lalpulsar_fits_header_list +0 -0
  163. lalapps/bin/lalpulsar_fits_overview +0 -0
  164. lalapps/bin/lalpulsar_fits_table_list +0 -0
  165. lalapps/bin/lalpulsar_frequency_evolution +0 -0
  166. lalapps/bin/lalpulsar_heterodyne +0 -0
  167. lalapps/bin/lalpulsar_parameter_estimation_nested +0 -0
  168. lalapps/bin/lalpulsar_spec_avg +0 -0
  169. lalapps/bin/lalpulsar_spec_avg_long +0 -0
  170. lalapps/bin/lalpulsar_spec_coherence +0 -0
  171. lalapps/bin/lalpulsar_splitSFTs +0 -0
  172. lalapps/bin/lalpulsar_ssbtodetector +0 -0
  173. lalapps/bin/lalpulsar_synthesizeBstatMC +0 -0
  174. lalapps/bin/lalpulsar_synthesizeLVStats +0 -0
  175. lalapps/bin/lalpulsar_synthesizeTransientStats +0 -0
  176. lalapps/bin/lalpulsar_version +0 -0
  177. lalapps/bin/lalsim-bh-qnmode +0 -0
  178. lalapps/bin/lalsim-bh-ringdown +0 -0
  179. lalapps/bin/lalsim-bh-sphwf +0 -0
  180. lalapps/bin/lalsim-burst +0 -0
  181. lalapps/bin/lalsim-detector-noise +0 -0
  182. lalapps/bin/lalsim-detector-strain +0 -0
  183. lalapps/bin/lalsim-inject +0 -0
  184. lalapps/bin/lalsim-inspiral +0 -0
  185. lalapps/bin/lalsim-ns-eos-table +0 -0
  186. lalapps/bin/lalsim-ns-mass-radius +0 -0
  187. lalapps/bin/lalsim-ns-params +0 -0
  188. lalapps/bin/lalsim-sgwb +0 -0
  189. lalapps/bin/lalsim-unicorn +0 -0
  190. lalapps/bin/lalsimulation_version +0 -0
  191. lalapps/cosmicstring.py +691 -0
  192. lalapps/data/BNSMasses.dat +65022 -0
  193. lalapps/data/CorrelationMatrix.csv +15 -0
  194. lalapps/data/LALSimNeutronStarEOS_ABHT_QMC_RMF1_META.dat +1882 -0
  195. lalapps/data/LALSimNeutronStarEOS_ABHT_QMC_RMF2_META.dat +1939 -0
  196. lalapps/data/LALSimNeutronStarEOS_ABHT_QMC_RMF3_META.dat +1784 -0
  197. lalapps/data/LALSimNeutronStarEOS_ABHT_QMC_RMF4_META.dat +2074 -0
  198. lalapps/data/LALSimNeutronStarEOS_ALF1.dat +435 -0
  199. lalapps/data/LALSimNeutronStarEOS_ALF2.dat +453 -0
  200. lalapps/data/LALSimNeutronStarEOS_ALF3.dat +441 -0
  201. lalapps/data/LALSimNeutronStarEOS_ALF4.dat +441 -0
  202. lalapps/data/LALSimNeutronStarEOS_AP1.dat +212 -0
  203. lalapps/data/LALSimNeutronStarEOS_AP2.dat +212 -0
  204. lalapps/data/LALSimNeutronStarEOS_AP3.dat +212 -0
  205. lalapps/data/LALSimNeutronStarEOS_AP4.dat +210 -0
  206. lalapps/data/LALSimNeutronStarEOS_APR.dat +500 -0
  207. lalapps/data/LALSimNeutronStarEOS_APR4_EPP.dat +1447 -0
  208. lalapps/data/LALSimNeutronStarEOS_BBB2.dat +84 -0
  209. lalapps/data/LALSimNeutronStarEOS_BGN1H1.dat +123 -0
  210. lalapps/data/LALSimNeutronStarEOS_BHF_BBB2.dat +499 -0
  211. lalapps/data/LALSimNeutronStarEOS_BL_CHIRAL_META.dat +1534 -0
  212. lalapps/data/LALSimNeutronStarEOS_BPAL12.dat +61 -0
  213. lalapps/data/LALSimNeutronStarEOS_BSK19.dat +310 -0
  214. lalapps/data/LALSimNeutronStarEOS_BSK20.dat +310 -0
  215. lalapps/data/LALSimNeutronStarEOS_BSK21.dat +310 -0
  216. lalapps/data/LALSimNeutronStarEOS_ENG.dat +108 -0
  217. lalapps/data/LALSimNeutronStarEOS_FPS.dat +129 -0
  218. lalapps/data/LALSimNeutronStarEOS_GMSR_BSK14_BSK24.dat +1010 -0
  219. lalapps/data/LALSimNeutronStarEOS_GMSR_DHSL59_BSK24.dat +1009 -0
  220. lalapps/data/LALSimNeutronStarEOS_GMSR_DHSL69_BSK24.dat +1009 -0
  221. lalapps/data/LALSimNeutronStarEOS_GMSR_F0_BSK24.dat +1010 -0
  222. lalapps/data/LALSimNeutronStarEOS_GMSR_H1_BSK24.dat +1009 -0
  223. lalapps/data/LALSimNeutronStarEOS_GMSR_H2_BSK24.dat +1010 -0
  224. lalapps/data/LALSimNeutronStarEOS_GMSR_H3_BSK24.dat +1010 -0
  225. lalapps/data/LALSimNeutronStarEOS_GMSR_H4_BSK24.dat +1010 -0
  226. lalapps/data/LALSimNeutronStarEOS_GMSR_H5_BSK24.dat +1009 -0
  227. lalapps/data/LALSimNeutronStarEOS_GMSR_LN55_BSK24.dat +1010 -0
  228. lalapps/data/LALSimNeutronStarEOS_GMSR_SLY5_BSK24.dat +1010 -0
  229. lalapps/data/LALSimNeutronStarEOS_GNH3.dat +71 -0
  230. lalapps/data/LALSimNeutronStarEOS_GPPVA_DD2_BSK24.dat +1009 -0
  231. lalapps/data/LALSimNeutronStarEOS_GPPVA_DDME2_BSK24.dat +1010 -0
  232. lalapps/data/LALSimNeutronStarEOS_GPPVA_FSU2H_BSK24.dat +1009 -0
  233. lalapps/data/LALSimNeutronStarEOS_GPPVA_FSU2_BSK24.dat +1010 -0
  234. lalapps/data/LALSimNeutronStarEOS_GPPVA_NL3WRL55_BSK24.dat +1010 -0
  235. lalapps/data/LALSimNeutronStarEOS_GS1.dat +136 -0
  236. lalapps/data/LALSimNeutronStarEOS_GS2.dat +100 -0
  237. lalapps/data/LALSimNeutronStarEOS_H1.dat +114 -0
  238. lalapps/data/LALSimNeutronStarEOS_H2.dat +114 -0
  239. lalapps/data/LALSimNeutronStarEOS_H3.dat +98 -0
  240. lalapps/data/LALSimNeutronStarEOS_H4.dat +664 -0
  241. lalapps/data/LALSimNeutronStarEOS_H5.dat +703 -0
  242. lalapps/data/LALSimNeutronStarEOS_H6.dat +509 -0
  243. lalapps/data/LALSimNeutronStarEOS_H7.dat +703 -0
  244. lalapps/data/LALSimNeutronStarEOS_HQC18.dat +388 -0
  245. lalapps/data/LALSimNeutronStarEOS_KDE0V.dat +500 -0
  246. lalapps/data/LALSimNeutronStarEOS_KDE0V1.dat +500 -0
  247. lalapps/data/LALSimNeutronStarEOS_KDE0V1_BSK24.dat +1388 -0
  248. lalapps/data/LALSimNeutronStarEOS_KDE0V_BSK24.dat +1398 -0
  249. lalapps/data/LALSimNeutronStarEOS_MPA1.dat +102 -0
  250. lalapps/data/LALSimNeutronStarEOS_MS1.dat +122 -0
  251. lalapps/data/LALSimNeutronStarEOS_MS1B.dat +126 -0
  252. lalapps/data/LALSimNeutronStarEOS_MS1B_PP.dat +1447 -0
  253. lalapps/data/LALSimNeutronStarEOS_MS1_PP.dat +1447 -0
  254. lalapps/data/LALSimNeutronStarEOS_MS2.dat +48 -0
  255. lalapps/data/LALSimNeutronStarEOS_PAL6.dat +148 -0
  256. lalapps/data/LALSimNeutronStarEOS_PCL2.dat +134 -0
  257. lalapps/data/LALSimNeutronStarEOS_PCP_BSK24_BSK24.dat +1010 -0
  258. lalapps/data/LALSimNeutronStarEOS_PS.dat +165 -0
  259. lalapps/data/LALSimNeutronStarEOS_QMC700.dat +117 -0
  260. lalapps/data/LALSimNeutronStarEOS_RG_SLY4_BSK24.dat +1010 -0
  261. lalapps/data/LALSimNeutronStarEOS_RS.dat +500 -0
  262. lalapps/data/LALSimNeutronStarEOS_RS_BSK24.dat +1356 -0
  263. lalapps/data/LALSimNeutronStarEOS_SK255.dat +500 -0
  264. lalapps/data/LALSimNeutronStarEOS_SK255_BSK24.dat +1066 -0
  265. lalapps/data/LALSimNeutronStarEOS_SK272.dat +500 -0
  266. lalapps/data/LALSimNeutronStarEOS_SKA.dat +500 -0
  267. lalapps/data/LALSimNeutronStarEOS_SKA_BSK24.dat +1433 -0
  268. lalapps/data/LALSimNeutronStarEOS_SKB.dat +500 -0
  269. lalapps/data/LALSimNeutronStarEOS_SKB_BSK24.dat +1373 -0
  270. lalapps/data/LALSimNeutronStarEOS_SKI2.dat +500 -0
  271. lalapps/data/LALSimNeutronStarEOS_SKI2_BSK24.dat +1348 -0
  272. lalapps/data/LALSimNeutronStarEOS_SKI3.dat +500 -0
  273. lalapps/data/LALSimNeutronStarEOS_SKI3_BSK24.dat +1355 -0
  274. lalapps/data/LALSimNeutronStarEOS_SKI4.dat +497 -0
  275. lalapps/data/LALSimNeutronStarEOS_SKI4_BSK24.dat +1348 -0
  276. lalapps/data/LALSimNeutronStarEOS_SKI5.dat +500 -0
  277. lalapps/data/LALSimNeutronStarEOS_SKI6.dat +500 -0
  278. lalapps/data/LALSimNeutronStarEOS_SKI6_BSK24.dat +1358 -0
  279. lalapps/data/LALSimNeutronStarEOS_SKMP.dat +498 -0
  280. lalapps/data/LALSimNeutronStarEOS_SKOP.dat +500 -0
  281. lalapps/data/LALSimNeutronStarEOS_SKOP_BSK24.dat +1373 -0
  282. lalapps/data/LALSimNeutronStarEOS_SLY.dat +99 -0
  283. lalapps/data/LALSimNeutronStarEOS_SLY2.dat +500 -0
  284. lalapps/data/LALSimNeutronStarEOS_SLY230A.dat +500 -0
  285. lalapps/data/LALSimNeutronStarEOS_SLY230A_BSK24.dat +1116 -0
  286. lalapps/data/LALSimNeutronStarEOS_SLY2_BSK24.dat +1106 -0
  287. lalapps/data/LALSimNeutronStarEOS_SLY4.dat +100 -0
  288. lalapps/data/LALSimNeutronStarEOS_SLY9.dat +498 -0
  289. lalapps/data/LALSimNeutronStarEOS_SLY9_BSK24.dat +1083 -0
  290. lalapps/data/LALSimNeutronStarEOS_SQM1.dat +176 -0
  291. lalapps/data/LALSimNeutronStarEOS_SQM2.dat +180 -0
  292. lalapps/data/LALSimNeutronStarEOS_SQM3.dat +176 -0
  293. lalapps/data/LALSimNeutronStarEOS_WFF1.dat +109 -0
  294. lalapps/data/LALSimNeutronStarEOS_WFF2.dat +109 -0
  295. lalapps/data/LALSimNeutronStarEOS_WFF3.dat +107 -0
  296. lalapps/data/LALSimNeutronStarEOS_XMLSLZ_DDLZ1_BSK24.dat +1227 -0
  297. lalapps/data/LALSimNeutronStarEOS_XMLSLZ_DDME2_BSK24.dat +1272 -0
  298. lalapps/data/LALSimNeutronStarEOS_XMLSLZ_DDMEX_BSK24.dat +1280 -0
  299. lalapps/data/LALSimNeutronStarEOS_XMLSLZ_GM1_BSK24.dat +1288 -0
  300. lalapps/data/LALSimNeutronStarEOS_XMLSLZ_MTVTC_BSK24.dat +1288 -0
  301. lalapps/data/LALSimNeutronStarEOS_XMLSLZ_NL3_BSK24.dat +1230 -0
  302. lalapps/data/LALSimNeutronStarEOS_XMLSLZ_PKDD_BSK24.dat +1288 -0
  303. lalapps/data/LALSimNeutronStarEOS_XMLSLZ_TM1_BSK24.dat +1288 -0
  304. lalapps/data/LALSimNeutronStarEOS_XMLSLZ_TW99_BSK24.dat +1288 -0
  305. lalapps/data/LIGO-P1200087-v18-AdV_BNS_OPTIMIZED.txt +3000 -0
  306. lalapps/data/LIGO-P1200087-v18-AdV_DESIGN.txt +3000 -0
  307. lalapps/data/LIGO-P1200087-v18-AdV_EARLY_HIGH.txt +3000 -0
  308. lalapps/data/LIGO-P1200087-v18-AdV_EARLY_LOW.txt +3000 -0
  309. lalapps/data/LIGO-P1200087-v18-AdV_LATE_HIGH.txt +3000 -0
  310. lalapps/data/LIGO-P1200087-v18-AdV_LATE_LOW.txt +3000 -0
  311. lalapps/data/LIGO-P1200087-v18-AdV_MID_HIGH.txt +3000 -0
  312. lalapps/data/LIGO-P1200087-v18-AdV_MID_LOW.txt +3000 -0
  313. lalapps/data/LIGO-P1200087-v18-aLIGO_BNS_OPTIMIZED.txt +3000 -0
  314. lalapps/data/LIGO-P1200087-v18-aLIGO_DESIGN.txt +3000 -0
  315. lalapps/data/LIGO-P1200087-v18-aLIGO_EARLY_HIGH.txt +3000 -0
  316. lalapps/data/LIGO-P1200087-v18-aLIGO_EARLY_LOW.txt +3000 -0
  317. lalapps/data/LIGO-P1200087-v18-aLIGO_LATE_HIGH.txt +3000 -0
  318. lalapps/data/LIGO-P1200087-v18-aLIGO_LATE_LOW.txt +3000 -0
  319. lalapps/data/LIGO-P1200087-v18-aLIGO_MID_HIGH.txt +3000 -0
  320. lalapps/data/LIGO-P1200087-v18-aLIGO_MID_LOW.txt +3000 -0
  321. lalapps/data/LIGO-P1600143-v18-CE.txt +3000 -0
  322. lalapps/data/LIGO-P1600143-v18-CE_Pessimistic.txt +3000 -0
  323. lalapps/data/LIGO-P1600143-v18-CE_Wideband.txt +3000 -0
  324. lalapps/data/LIGO-P1600143-v18-ET_D.txt +3000 -0
  325. lalapps/data/LIGO-T0900288-v3-BHBH_20deg.txt +3000 -0
  326. lalapps/data/LIGO-T0900288-v3-High_Freq.txt +3000 -0
  327. lalapps/data/LIGO-T0900288-v3-NO_SRM.txt +3000 -0
  328. lalapps/data/LIGO-T0900288-v3-NSNS_Opt.txt +3000 -0
  329. lalapps/data/LIGO-T0900288-v3-ZERO_DET_high_P.txt +3000 -0
  330. lalapps/data/LIGO-T0900288-v3-ZERO_DET_low_P.txt +3000 -0
  331. lalapps/data/LIGO-T1600593-v1-KAGRA_Design.txt +4000 -0
  332. lalapps/data/LIGO-T1600593-v1-KAGRA_Early.txt +4000 -0
  333. lalapps/data/LIGO-T1600593-v1-KAGRA_Late.txt +4000 -0
  334. lalapps/data/LIGO-T1600593-v1-KAGRA_Mid.txt +4000 -0
  335. lalapps/data/LIGO-T1600593-v1-KAGRA_Opening.txt +4000 -0
  336. lalapps/data/LIGO-T1800042-v5-aLIGO_APLUS.txt +3000 -0
  337. lalapps/data/LIGO-T1800044-v5-aLIGO_DESIGN.txt +3000 -0
  338. lalapps/data/LIGO-T1800545-v1-AdV_O3low.txt +3000 -0
  339. lalapps/data/LIGO-T1800545-v1-AdV_O4.txt +3000 -0
  340. lalapps/data/LIGO-T1800545-v1-AdV_O4intermediate.txt +3000 -0
  341. lalapps/data/LIGO-T1800545-v1-KAGRA_128Mpc.txt +1000 -0
  342. lalapps/data/LIGO-T1800545-v1-KAGRA_25Mpc.txt +1000 -0
  343. lalapps/data/LIGO-T1800545-v1-KAGRA_80Mpc.txt +1000 -0
  344. lalapps/data/LIGO-T1800545-v1-aLIGO_140Mpc.txt +1000 -0
  345. lalapps/data/LIGO-T1800545-v1-aLIGO_175Mpc.txt +2792 -0
  346. lalapps/data/LIGO-T1800545-v1-aLIGO_O3low.txt +2792 -0
  347. lalapps/data/bimodalMeans.csv +3 -0
  348. lalapps/data/config_tiger_example.ini +150 -0
  349. lalapps/data/fiducialBBH.xml +67 -0
  350. lalapps/data/fiducialBNS.xml +67 -0
  351. lalapps/data/inspsrcs100Mpc.errors +38735 -0
  352. lalapps/data/lalinference_pipe_example.ini +573 -0
  353. lalapps/data/lib_pipe_example.ini +303 -0
  354. lalapps/data/power_pipe.ini +129 -0
  355. lalapps/data/unimodalMeans.csv +2 -0
  356. lalapps/git_version.py +64 -0
  357. lalburst/SimBurstUtils.py +324 -0
  358. lalburst/SnglBurstUtils.py +367 -0
  359. lalburst/__init__.py +7 -0
  360. lalburst/_lalburst.cpython-314t-x86_64-linux-gnu.so +0 -0
  361. lalburst/_lalburst_swig.py +16 -0
  362. lalburst/binjfind.py +824 -0
  363. lalburst/bucluster.py +409 -0
  364. lalburst/burca.py +315 -0
  365. lalburst/burca_tailor.py +349 -0
  366. lalburst/cafe.py +579 -0
  367. lalburst/calc_likelihood.py +145 -0
  368. lalburst/cs_gamma.cpython-314t-x86_64-linux-gnu.so +0 -0
  369. lalburst/date.py +118 -0
  370. lalburst/git_version.py +64 -0
  371. lalburst/offsetvector.py +278 -0
  372. lalburst/packing.py +170 -0
  373. lalburst/power.py +1457 -0
  374. lalburst/snglcluster.py +136 -0
  375. lalburst/snglcoinc.py +2637 -0
  376. lalburst/stringutils.py +607 -0
  377. lalburst/timeslides.py +236 -0
  378. lalframe/__init__.py +7 -0
  379. lalframe/_lalframe.cpython-314t-x86_64-linux-gnu.so +0 -0
  380. lalframe/_lalframe_swig.py +14 -0
  381. lalframe/frread.py +324 -0
  382. lalframe/git_version.py +64 -0
  383. lalframe/utils/__init__.py +25 -0
  384. lalframe/utils/frtools.py +61 -0
  385. lalinference/__init__.py +7 -0
  386. lalinference/_bayespputils.cpython-314t-x86_64-linux-gnu.so +0 -0
  387. lalinference/_lalinference.cpython-314t-x86_64-linux-gnu.so +0 -0
  388. lalinference/_lalinference_swig.py +19 -0
  389. lalinference/bayespputils.py +7479 -0
  390. lalinference/bayestar/__init__.py +2 -0
  391. lalinference/bayestar/deprecation.py +72 -0
  392. lalinference/git_version.py +64 -0
  393. lalinference/imrtgr/__init__.py +0 -0
  394. lalinference/imrtgr/imrtgrutils.py +168 -0
  395. lalinference/imrtgr/nrutils.py +1366 -0
  396. lalinference/imrtgr/pneqns.py +250 -0
  397. lalinference/io/__init__.py +31 -0
  398. lalinference/io/hdf5.py +365 -0
  399. lalinference/lalinference_pipe_utils.py +3617 -0
  400. lalinference/nest2pos.py +151 -0
  401. lalinference/plot/__init__.py +34 -0
  402. lalinference/plot/spindisk.py +104 -0
  403. lalinference/tiger/__init__.py +0 -0
  404. lalinference/tiger/make_injtimes.py +634 -0
  405. lalinference/tiger/omegascans_dag.py +691 -0
  406. lalinference/tiger/postproc.py +1338 -0
  407. lalinference/wrapper.py +231 -0
  408. lalinspiral/__init__.py +7 -0
  409. lalinspiral/_lalinspiral.cpython-314t-x86_64-linux-gnu.so +0 -0
  410. lalinspiral/_lalinspiral_swig.py +18 -0
  411. lalinspiral/_thinca.cpython-314t-x86_64-linux-gnu.so +0 -0
  412. lalinspiral/git_version.py +64 -0
  413. lalinspiral/inspinjfind.py +485 -0
  414. lalinspiral/thinca.py +509 -0
  415. lalmetaio/__init__.py +7 -0
  416. lalmetaio/_lalmetaio.cpython-314t-x86_64-linux-gnu.so +0 -0
  417. lalmetaio/_lalmetaio_swig.py +14 -0
  418. lalmetaio/git_version.py +64 -0
  419. lalpulsar/NstarTools.py +259 -0
  420. lalpulsar/PulsarParametersWrapper.py +938 -0
  421. lalpulsar/__init__.py +7 -0
  422. lalpulsar/_lalpulsar.cpython-314t-x86_64-linux-gnu.so +0 -0
  423. lalpulsar/_lalpulsar_swig.py +17 -0
  424. lalpulsar/git_version.py +64 -0
  425. lalpulsar/knope_utils.py +6497 -0
  426. lalpulsar/lineFileParser.py +264 -0
  427. lalpulsar/metric_utils.py +78 -0
  428. lalpulsar/piecewise_model/__init__.py +7 -0
  429. lalpulsar/piecewise_model/basis_functions.py +156 -0
  430. lalpulsar/piecewise_model/class_definitions.py +323 -0
  431. lalpulsar/piecewise_model/errors.py +37 -0
  432. lalpulsar/piecewise_model/estimating_knots.py +833 -0
  433. lalpulsar/piecewise_model/gte_and_other_methods.py +189 -0
  434. lalpulsar/piecewise_model/mols_for_gte.py +269 -0
  435. lalpulsar/piecewise_model/pw_fstat.py +813 -0
  436. lalpulsar/piecewise_model/pw_model_simulations.py +156 -0
  437. lalpulsar/piecewise_model/sampling_methods.py +186 -0
  438. lalpulsar/piecewise_model/semicoherent_metric_methods.py +375 -0
  439. lalpulsar/piecewise_model/tbank_estimates.py +293 -0
  440. lalpulsar/public_sft_directory.py +82 -0
  441. lalpulsar/pulsarhtmlutils.py +1395 -0
  442. lalpulsar/pulsarpputils.py +3638 -0
  443. lalpulsar/simulateCW.py +602 -0
  444. lalpulsar/simulateHeterodynedCW.py +591 -0
  445. lalsimulation/__init__.py +7 -0
  446. lalsimulation/_lalsimulation.cpython-314t-x86_64-linux-gnu.so +0 -0
  447. lalsimulation/_lalsimulation_swig.py +14 -0
  448. lalsimulation/git_version.py +64 -0
  449. lalsimulation/gwsignal/__init__.py +9 -0
  450. lalsimulation/gwsignal/core/__init__.py +2 -0
  451. lalsimulation/gwsignal/core/conditioning_subroutines.py +196 -0
  452. lalsimulation/gwsignal/core/errors.py +136 -0
  453. lalsimulation/gwsignal/core/gw.py +206 -0
  454. lalsimulation/gwsignal/core/parameter_conventions.py +122 -0
  455. lalsimulation/gwsignal/core/utils.py +329 -0
  456. lalsimulation/gwsignal/core/waveform.py +725 -0
  457. lalsimulation/gwsignal/core/waveform_conditioning.py +455 -0
  458. lalsimulation/gwsignal/models/__init__.py +29 -0
  459. lalsimulation/gwsignal/models/pyseobnr_model.py +452 -0
  460. lalsimulation/nrfits/NRSur3dq8Remnant.py +92 -0
  461. lalsimulation/nrfits/NRSur7dq4Remnant.py +469 -0
  462. lalsimulation/nrfits/__init__.py +1 -0
  463. lalsimulation/nrfits/eval_fits.py +364 -0
  464. lalsimulation/nrfits/nrfits.py +78 -0
  465. lalsimulation/nrfits/pn_spin_evolution_wrapper.py +92 -0
  466. lalsimulation/nrfits/quaternion_utils.py +74 -0
  467. lalsimulation/tilts_at_infinity/__init__.py +2 -0
  468. lalsimulation/tilts_at_infinity/calc_tilts_prec_avg_regularized.py +1424 -0
  469. lalsimulation/tilts_at_infinity/hybrid_spin_evolution.py +461 -0
  470. lalsimulation/tilts_at_infinity/tilts_at_infinity_utils.py +167 -0
  471. lalsuite-7.26.2.dev20251218.data/scripts/cbcBayesBurstPPAnalysis +305 -0
  472. lalsuite-7.26.2.dev20251218.data/scripts/cbcBayesBurstPostProc +1364 -0
  473. lalsuite-7.26.2.dev20251218.data/scripts/cbcBayesCombinePTMCMCh5s +100 -0
  474. lalsuite-7.26.2.dev20251218.data/scripts/cbcBayesCombinePosteriors +235 -0
  475. lalsuite-7.26.2.dev20251218.data/scripts/cbcBayesCompPos +1121 -0
  476. lalsuite-7.26.2.dev20251218.data/scripts/cbcBayesDIEvidence +68 -0
  477. lalsuite-7.26.2.dev20251218.data/scripts/cbcBayesGraceDBinfo +182 -0
  478. lalsuite-7.26.2.dev20251218.data/scripts/cbcBayesMCMC2pos +314 -0
  479. lalsuite-7.26.2.dev20251218.data/scripts/cbcBayesPPAnalysis +322 -0
  480. lalsuite-7.26.2.dev20251218.data/scripts/cbcBayesPlotSpinDisk +42 -0
  481. lalsuite-7.26.2.dev20251218.data/scripts/cbcBayesPosToSimBurst +227 -0
  482. lalsuite-7.26.2.dev20251218.data/scripts/cbcBayesPosToSimInspiral +307 -0
  483. lalsuite-7.26.2.dev20251218.data/scripts/cbcBayesPostProc +1345 -0
  484. lalsuite-7.26.2.dev20251218.data/scripts/cbcBayesThermoInt +107 -0
  485. lalsuite-7.26.2.dev20251218.data/scripts/imrtgr_imr_consistency_test +796 -0
  486. lalsuite-7.26.2.dev20251218.data/scripts/lal_cache +6 -0
  487. lalsuite-7.26.2.dev20251218.data/scripts/lal_fftw_wisdom +6 -0
  488. lalsuite-7.26.2.dev20251218.data/scripts/lal_fftwf_wisdom +6 -0
  489. lalsuite-7.26.2.dev20251218.data/scripts/lal_path2cache +148 -0
  490. lalsuite-7.26.2.dev20251218.data/scripts/lal_searchsum2cache +172 -0
  491. lalsuite-7.26.2.dev20251218.data/scripts/lal_simd_detect +6 -0
  492. lalsuite-7.26.2.dev20251218.data/scripts/lal_tconvert +6 -0
  493. lalsuite-7.26.2.dev20251218.data/scripts/lal_version +6 -0
  494. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_ComputeAntennaPattern +6 -0
  495. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_ComputeFstatBenchmark +6 -0
  496. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_ComputeFstatLatticeCount +6 -0
  497. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_ComputeFstatMCUpperLimit +6 -0
  498. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_ComputeFstatistic_v2 +6 -0
  499. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_ComputePSD +6 -0
  500. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_CopySFTs +6 -0
  501. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_DistanceVsMass +6 -0
  502. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_DriveHoughMulti +6 -0
  503. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_FstatMetric_v2 +6 -0
  504. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_HierarchSearchGCT +6 -0
  505. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_HierarchicalSearch +6 -0
  506. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_MakeSFTDAG +6 -0
  507. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_MakeSFTs +6 -0
  508. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_Makefakedata_v4 +6 -0
  509. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_Makefakedata_v5 +6 -0
  510. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_PredictFstat +6 -0
  511. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_PrintDetectorState +6 -0
  512. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_SFTclean +6 -0
  513. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_SFTvalidate +6 -0
  514. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_StringAddFrame +6 -0
  515. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_StringSearch +6 -0
  516. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_Weave +6 -0
  517. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_WeaveCompare +6 -0
  518. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_WeaveConcat +6 -0
  519. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_WeaveSetup +6 -0
  520. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_WriteSFTsfromSFDBs +6 -0
  521. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_animate +6 -0
  522. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_binj +6 -0
  523. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_blindinj +6 -0
  524. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_cache +6 -0
  525. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_cafe +99 -0
  526. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_calfacs +6 -0
  527. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_cbc_stochasticbank +6 -0
  528. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_chirplen +6 -0
  529. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_coh_PTF_inspiral +6 -0
  530. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_coinj +6 -0
  531. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_combine_crosscorr_toplists +6 -0
  532. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_compareFstats +6 -0
  533. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_compareSFTs +6 -0
  534. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_cosmicstring_pipe +525 -0
  535. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_create_time_correction_ephemeris +6 -0
  536. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_dumpSFT +6 -0
  537. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_effdist +6 -0
  538. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_exc_resp +6 -0
  539. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_fftw_wisdom +6 -0
  540. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_fftwf_wisdom +6 -0
  541. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_fits_header_getval +6 -0
  542. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_fits_header_list +6 -0
  543. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_fits_overview +6 -0
  544. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_fits_table_list +6 -0
  545. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_fr_ninja +6 -0
  546. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_frextr +6 -0
  547. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_frinfo +6 -0
  548. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_frjoin +6 -0
  549. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_frread +6 -0
  550. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_frview +6 -0
  551. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_gwf2xml +6 -0
  552. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_heterodyne_pulsar +6 -0
  553. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_inspawgfile +6 -0
  554. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_inspfrinj +6 -0
  555. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_inspinj +6 -0
  556. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_inspiralDistance +6 -0
  557. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_knope +6 -0
  558. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_knope_automation_script +6 -0
  559. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_knope_collate_results +6 -0
  560. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_knope_result_page +6 -0
  561. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_makeblindinj +6 -0
  562. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_makeblindinj_himass +6 -0
  563. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_ninja +6 -0
  564. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_path2cache +6 -0
  565. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_power +6 -0
  566. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_power_likelihood_pipe +219 -0
  567. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_power_pipe +417 -0
  568. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_pulsar_crosscorr_v2 +6 -0
  569. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_pulsar_frequency_evolution +6 -0
  570. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_pulsar_parameter_estimation_nested +6 -0
  571. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_random_bank +6 -0
  572. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_randombank +6 -0
  573. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_run_pulsar_crosscorr_v2 +6 -0
  574. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_searchsum2cache +6 -0
  575. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_spec_avg +6 -0
  576. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_spec_avg_long +6 -0
  577. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_spec_coherence +6 -0
  578. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_spininj +6 -0
  579. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_splitSFTs +6 -0
  580. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_splitbank +6 -0
  581. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_ssbtodetector +6 -0
  582. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_string_apply_vetoes +171 -0
  583. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_string_calc_likelihood +172 -0
  584. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_string_contour_plotter +141 -0
  585. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_string_contour_plotter_largeloops +133 -0
  586. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_string_cs_gamma +110 -0
  587. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_string_cs_gamma_largeloops +119 -0
  588. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_string_final +1064 -0
  589. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_string_meas_likelihood +264 -0
  590. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_string_plot_binj +543 -0
  591. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_string_plot_likelihood +380 -0
  592. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_synthesizeBstatMC +6 -0
  593. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_synthesizeLVStats +6 -0
  594. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_synthesizeTransientStats +6 -0
  595. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_tconvert +6 -0
  596. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_tmpltbank +6 -0
  597. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_version +6 -0
  598. lalsuite-7.26.2.dev20251218.data/scripts/lalapps_xtefitstoframe +6 -0
  599. lalsuite-7.26.2.dev20251218.data/scripts/lalburst_cluster +156 -0
  600. lalsuite-7.26.2.dev20251218.data/scripts/lalburst_coinc +224 -0
  601. lalsuite-7.26.2.dev20251218.data/scripts/lalburst_cut +425 -0
  602. lalsuite-7.26.2.dev20251218.data/scripts/lalburst_gen_timeslides +254 -0
  603. lalsuite-7.26.2.dev20251218.data/scripts/lalburst_inj_pic +254 -0
  604. lalsuite-7.26.2.dev20251218.data/scripts/lalburst_injfind +170 -0
  605. lalsuite-7.26.2.dev20251218.data/scripts/lalburst_plot_tisi +165 -0
  606. lalsuite-7.26.2.dev20251218.data/scripts/lalburst_power_calc_likelihood +182 -0
  607. lalsuite-7.26.2.dev20251218.data/scripts/lalburst_power_final +1369 -0
  608. lalsuite-7.26.2.dev20251218.data/scripts/lalburst_power_meas_likelihood +206 -0
  609. lalsuite-7.26.2.dev20251218.data/scripts/lalburst_power_plot_binj +934 -0
  610. lalsuite-7.26.2.dev20251218.data/scripts/lalburst_power_plot_binjtf +302 -0
  611. lalsuite-7.26.2.dev20251218.data/scripts/lalburst_version +6 -0
  612. lalsuite-7.26.2.dev20251218.data/scripts/lalfr-cat +6 -0
  613. lalsuite-7.26.2.dev20251218.data/scripts/lalfr-cksum +6 -0
  614. lalsuite-7.26.2.dev20251218.data/scripts/lalfr-cut +6 -0
  615. lalsuite-7.26.2.dev20251218.data/scripts/lalfr-dump +6 -0
  616. lalsuite-7.26.2.dev20251218.data/scripts/lalfr-fmt +6 -0
  617. lalsuite-7.26.2.dev20251218.data/scripts/lalfr-paste +6 -0
  618. lalsuite-7.26.2.dev20251218.data/scripts/lalfr-print +6 -0
  619. lalsuite-7.26.2.dev20251218.data/scripts/lalfr-split +6 -0
  620. lalsuite-7.26.2.dev20251218.data/scripts/lalfr-stat +6 -0
  621. lalsuite-7.26.2.dev20251218.data/scripts/lalfr-stream +6 -0
  622. lalsuite-7.26.2.dev20251218.data/scripts/lalfr-vis +6 -0
  623. lalsuite-7.26.2.dev20251218.data/scripts/lalframe_version +6 -0
  624. lalsuite-7.26.2.dev20251218.data/scripts/lalinference_bench +6 -0
  625. lalsuite-7.26.2.dev20251218.data/scripts/lalinference_burst +6 -0
  626. lalsuite-7.26.2.dev20251218.data/scripts/lalinference_burst_pp_pipe +220 -0
  627. lalsuite-7.26.2.dev20251218.data/scripts/lalinference_coherence_test +139 -0
  628. lalsuite-7.26.2.dev20251218.data/scripts/lalinference_compute_roq_weights +404 -0
  629. lalsuite-7.26.2.dev20251218.data/scripts/lalinference_cpnest +58 -0
  630. lalsuite-7.26.2.dev20251218.data/scripts/lalinference_datadump +6 -0
  631. lalsuite-7.26.2.dev20251218.data/scripts/lalinference_evolve_spins_and_append_samples +202 -0
  632. lalsuite-7.26.2.dev20251218.data/scripts/lalinference_injectedlike +6 -0
  633. lalsuite-7.26.2.dev20251218.data/scripts/lalinference_merge_posteriors +57 -0
  634. lalsuite-7.26.2.dev20251218.data/scripts/lalinference_mpi_wrapper +6 -0
  635. lalsuite-7.26.2.dev20251218.data/scripts/lalinference_multi_pipe +144 -0
  636. lalsuite-7.26.2.dev20251218.data/scripts/lalinference_nest +6 -0
  637. lalsuite-7.26.2.dev20251218.data/scripts/lalinference_nest2pos +286 -0
  638. lalsuite-7.26.2.dev20251218.data/scripts/lalinference_pipe +512 -0
  639. lalsuite-7.26.2.dev20251218.data/scripts/lalinference_pp_pipe +229 -0
  640. lalsuite-7.26.2.dev20251218.data/scripts/lalinference_review_test +362 -0
  641. lalsuite-7.26.2.dev20251218.data/scripts/lalinference_version +6 -0
  642. lalsuite-7.26.2.dev20251218.data/scripts/lalinspiral_injfind +206 -0
  643. lalsuite-7.26.2.dev20251218.data/scripts/lalinspiral_thinca +240 -0
  644. lalsuite-7.26.2.dev20251218.data/scripts/lalinspiral_version +6 -0
  645. lalsuite-7.26.2.dev20251218.data/scripts/lalmetaio_version +6 -0
  646. lalsuite-7.26.2.dev20251218.data/scripts/lalpulsar_ComputeAntennaPattern +6 -0
  647. lalsuite-7.26.2.dev20251218.data/scripts/lalpulsar_ComputeFstatBenchmark +6 -0
  648. lalsuite-7.26.2.dev20251218.data/scripts/lalpulsar_ComputeFstatLatticeCount +6 -0
  649. lalsuite-7.26.2.dev20251218.data/scripts/lalpulsar_ComputeFstatMCUpperLimit +6 -0
  650. lalsuite-7.26.2.dev20251218.data/scripts/lalpulsar_ComputeFstatistic_v2 +6 -0
  651. lalsuite-7.26.2.dev20251218.data/scripts/lalpulsar_ComputePSD +6 -0
  652. lalsuite-7.26.2.dev20251218.data/scripts/lalpulsar_CopyPublicSFTs +216 -0
  653. lalsuite-7.26.2.dev20251218.data/scripts/lalpulsar_DriveHoughMulti +6 -0
  654. lalsuite-7.26.2.dev20251218.data/scripts/lalpulsar_FstatMetric_v2 +6 -0
  655. lalsuite-7.26.2.dev20251218.data/scripts/lalpulsar_HierarchSearchGCT +6 -0
  656. lalsuite-7.26.2.dev20251218.data/scripts/lalpulsar_HierarchicalSearch +6 -0
  657. lalsuite-7.26.2.dev20251218.data/scripts/lalpulsar_MakeSFTDAG +1142 -0
  658. lalsuite-7.26.2.dev20251218.data/scripts/lalpulsar_MakeSFTs +6 -0
  659. lalsuite-7.26.2.dev20251218.data/scripts/lalpulsar_Makefakedata_v4 +6 -0
  660. lalsuite-7.26.2.dev20251218.data/scripts/lalpulsar_Makefakedata_v5 +6 -0
  661. lalsuite-7.26.2.dev20251218.data/scripts/lalpulsar_MoveSFTs +208 -0
  662. lalsuite-7.26.2.dev20251218.data/scripts/lalpulsar_PiecewiseSearch +963 -0
  663. lalsuite-7.26.2.dev20251218.data/scripts/lalpulsar_PredictFstat +6 -0
  664. lalsuite-7.26.2.dev20251218.data/scripts/lalpulsar_PrintDetectorState +6 -0
  665. lalsuite-7.26.2.dev20251218.data/scripts/lalpulsar_SFTclean +6 -0
  666. lalsuite-7.26.2.dev20251218.data/scripts/lalpulsar_SFTvalidate +6 -0
  667. lalsuite-7.26.2.dev20251218.data/scripts/lalpulsar_Weave +6 -0
  668. lalsuite-7.26.2.dev20251218.data/scripts/lalpulsar_WeaveCompare +6 -0
  669. lalsuite-7.26.2.dev20251218.data/scripts/lalpulsar_WeaveConcat +6 -0
  670. lalsuite-7.26.2.dev20251218.data/scripts/lalpulsar_WeaveSetup +6 -0
  671. lalsuite-7.26.2.dev20251218.data/scripts/lalpulsar_WriteSFTsfromSFDBs +6 -0
  672. lalsuite-7.26.2.dev20251218.data/scripts/lalpulsar_compareFstats +6 -0
  673. lalsuite-7.26.2.dev20251218.data/scripts/lalpulsar_compareSFTs +6 -0
  674. lalsuite-7.26.2.dev20251218.data/scripts/lalpulsar_create_time_correction_ephemeris +6 -0
  675. lalsuite-7.26.2.dev20251218.data/scripts/lalpulsar_crosscorr_v2 +6 -0
  676. lalsuite-7.26.2.dev20251218.data/scripts/lalpulsar_dumpSFT +6 -0
  677. lalsuite-7.26.2.dev20251218.data/scripts/lalpulsar_fits_header_getval +6 -0
  678. lalsuite-7.26.2.dev20251218.data/scripts/lalpulsar_fits_header_list +6 -0
  679. lalsuite-7.26.2.dev20251218.data/scripts/lalpulsar_fits_overview +6 -0
  680. lalsuite-7.26.2.dev20251218.data/scripts/lalpulsar_fits_table_list +6 -0
  681. lalsuite-7.26.2.dev20251218.data/scripts/lalpulsar_frequency_evolution +6 -0
  682. lalsuite-7.26.2.dev20251218.data/scripts/lalpulsar_heterodyne +6 -0
  683. lalsuite-7.26.2.dev20251218.data/scripts/lalpulsar_knope +145 -0
  684. lalsuite-7.26.2.dev20251218.data/scripts/lalpulsar_knope_automation_script +731 -0
  685. lalsuite-7.26.2.dev20251218.data/scripts/lalpulsar_knope_collate_results +675 -0
  686. lalsuite-7.26.2.dev20251218.data/scripts/lalpulsar_knope_result_page +2977 -0
  687. lalsuite-7.26.2.dev20251218.data/scripts/lalpulsar_parameter_estimation_nested +6 -0
  688. lalsuite-7.26.2.dev20251218.data/scripts/lalpulsar_spec_avg +6 -0
  689. lalsuite-7.26.2.dev20251218.data/scripts/lalpulsar_spec_avg_long +6 -0
  690. lalsuite-7.26.2.dev20251218.data/scripts/lalpulsar_spec_coherence +6 -0
  691. lalsuite-7.26.2.dev20251218.data/scripts/lalpulsar_splitSFTs +6 -0
  692. lalsuite-7.26.2.dev20251218.data/scripts/lalpulsar_ssbtodetector +6 -0
  693. lalsuite-7.26.2.dev20251218.data/scripts/lalpulsar_synthesizeBstatMC +6 -0
  694. lalsuite-7.26.2.dev20251218.data/scripts/lalpulsar_synthesizeLVStats +6 -0
  695. lalsuite-7.26.2.dev20251218.data/scripts/lalpulsar_synthesizeTransientStats +6 -0
  696. lalsuite-7.26.2.dev20251218.data/scripts/lalpulsar_version +6 -0
  697. lalsuite-7.26.2.dev20251218.data/scripts/lalsim-bh-qnmode +6 -0
  698. lalsuite-7.26.2.dev20251218.data/scripts/lalsim-bh-ringdown +6 -0
  699. lalsuite-7.26.2.dev20251218.data/scripts/lalsim-bh-sphwf +6 -0
  700. lalsuite-7.26.2.dev20251218.data/scripts/lalsim-burst +6 -0
  701. lalsuite-7.26.2.dev20251218.data/scripts/lalsim-detector-noise +6 -0
  702. lalsuite-7.26.2.dev20251218.data/scripts/lalsim-detector-strain +6 -0
  703. lalsuite-7.26.2.dev20251218.data/scripts/lalsim-inject +6 -0
  704. lalsuite-7.26.2.dev20251218.data/scripts/lalsim-inspiral +6 -0
  705. lalsuite-7.26.2.dev20251218.data/scripts/lalsim-ns-eos-table +6 -0
  706. lalsuite-7.26.2.dev20251218.data/scripts/lalsim-ns-mass-radius +6 -0
  707. lalsuite-7.26.2.dev20251218.data/scripts/lalsim-ns-params +6 -0
  708. lalsuite-7.26.2.dev20251218.data/scripts/lalsim-sgwb +6 -0
  709. lalsuite-7.26.2.dev20251218.data/scripts/lalsim-unicorn +6 -0
  710. lalsuite-7.26.2.dev20251218.data/scripts/lalsimulation_version +6 -0
  711. lalsuite-7.26.2.dev20251218.dist-info/METADATA +90 -0
  712. lalsuite-7.26.2.dev20251218.dist-info/RECORD +733 -0
  713. lalsuite-7.26.2.dev20251218.dist-info/WHEEL +5 -0
  714. lalsuite-7.26.2.dev20251218.dist-info/licenses/COPYING +339 -0
  715. lalsuite-7.26.2.dev20251218.dist-info/top_level.txt +9 -0
  716. lalsuite.libs/libcfitsio-729ee1b7.so.10.0.0 +0 -0
  717. lalsuite.libs/libfftw3-6b983104.so.3.5.5 +0 -0
  718. lalsuite.libs/libfftw3f-b4465a35.so.3.5.5 +0 -0
  719. lalsuite.libs/libframel-8cf74372.so.8.48.4 +0 -0
  720. lalsuite.libs/libgsl-e30be130.so.28.0.0 +0 -0
  721. lalsuite.libs/libgslcblas-460f042a.so.0.0.0 +0 -0
  722. lalsuite.libs/libhdf5-d02936e2.so.310.5.1 +0 -0
  723. lalsuite.libs/libhdf5_hl-0e40b553.so.310.0.6 +0 -0
  724. lalsuite.libs/liblal-bd4575d4.so.20.5.0 +0 -0
  725. lalsuite.libs/liblalburst-183caa97.so.8.0.0 +0 -0
  726. lalsuite.libs/liblalframe-b2539a8a.so.14.0.3 +0 -0
  727. lalsuite.libs/liblalinference-b273091a.so.23.1.7 +0 -0
  728. lalsuite.libs/liblalinspiral-37f93c6c.so.18.0.2 +0 -0
  729. lalsuite.libs/liblalmetaio-f04c856f.so.11.0.1 +0 -0
  730. lalsuite.libs/liblalpulsar-950e7dfd.so.30.1.1 +0 -0
  731. lalsuite.libs/liblalsimulation-abda47f7.so.37.2.0 +0 -0
  732. lalsuite.libs/liblalsupport-ad162801.so.14.4.0 +0 -0
  733. lalsuite.libs/libmetaio-abda72ec.so.1.1.0 +0 -0
lal/rate.py ADDED
@@ -0,0 +1,2455 @@
1
+ # Copyright (C) 2006--2021 Kipp Cannon
2
+ #
3
+ # This program is free software; you can redistribute it and/or modify it
4
+ # under the terms of the GNU General Public License as published by the
5
+ # Free Software Foundation; either version 2 of the License, or (at your
6
+ # option) any later version.
7
+ #
8
+ # This program is distributed in the hope that it will be useful, but
9
+ # WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
11
+ # Public License for more details.
12
+ #
13
+ # You should have received a copy of the GNU General Public License along
14
+ # with this program; if not, write to the Free Software Foundation, Inc.,
15
+ # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16
+
17
+
18
+ #
19
+ # =============================================================================
20
+ #
21
+ # Preamble
22
+ #
23
+ # =============================================================================
24
+ #
25
+
26
+
27
+ """
28
+ This module provides facilities for studying impulsive events. A number of
29
+ multi-dimensional binning functions are provided, as well as code to
30
+ convolve binned data with integral- and phase-preserving window functions
31
+ to produce smoothed representations of data sets. This is particularly
32
+ well suited for use in computing moving-average rate data from collections
33
+ of impulsive events, elliminating binning artifacts from histograms, and
34
+ smoothing contour plots.
35
+ """
36
+
37
+
38
+ from functools import reduce
39
+ try:
40
+ from fpconst import PosInf, NegInf
41
+ except ImportError:
42
+ # fpconst is not part of the standard library and might not
43
+ # be available
44
+ PosInf = float("+inf")
45
+ NegInf = float("-inf")
46
+ import itertools
47
+ import math
48
+ import numpy
49
+ import random
50
+ import scipy
51
+ __numpy__version__ = tuple(map(int, numpy.__version__.strip().split(".")[:2]))
52
+ __scipy__version__ = tuple(map(int, scipy.__version__.strip().split(".")[:2]))
53
+ # FIXME Uncomment these lines when the interpolator problem is fixed or when we
54
+ # figure out the correct version numbers to check for
55
+ '''
56
+ if __scipy__version__ >= (0, 9) and __numpy__version__ >= (1, 7):
57
+ from scipy.interpolate import interp1d, interp2d, LinearNDInterpolator
58
+ else:
59
+ # pre scipy/numpy 0.9/1.7 had busted/missing interpolation code.
60
+ # replacements are provided below
61
+ pass
62
+ '''
63
+ from scipy.signal import signaltools
64
+
65
+ import igwn_segments as segments
66
+
67
+ from igwn_ligolw import ligolw
68
+ from igwn_ligolw import types as ligolw_types
69
+ import lal
70
+ from . import iterutils
71
+ from . import git_version
72
+
73
+
74
+ __author__ = "Kipp Cannon <kipp.cannon@ligo.org>"
75
+ __version__ = "git id %s" % git_version.id
76
+ __date__ = git_version.date
77
+
78
+
79
+ #
80
+ # =============================================================================
81
+ #
82
+ # Bins
83
+ #
84
+ # =============================================================================
85
+ #
86
+
87
+
88
+ class Bins(object):
89
+ """
90
+ Parent class for 1-dimensional binnings. This class is not
91
+ intended to be used directly, but to be subclassed for use in real
92
+ bins classes.
93
+ """
94
+ def __init__(self):
95
+ """
96
+ Initialize a Bins instance. Subclasses must override this
97
+ method.
98
+ """
99
+ raise NotImplementedError
100
+
101
+ def __len__(self):
102
+ """
103
+ The number of bins in the binning. Subclasses must
104
+ override this method.
105
+ """
106
+ raise NotImplementedError
107
+
108
+ def __eq__(self, other):
109
+ """
110
+ Two binnings are the same if they are instances of the same
111
+ class, and describe the same binnings. Subclasses should
112
+ override this method but need not.
113
+ """
114
+ raise NotImplementedError
115
+
116
+ def __getitem__(self, x):
117
+ """
118
+ Convert a co-ordinate to a bin index. The co-ordinate can
119
+ be a single value, or a Python slice instance describing a
120
+ range of values. If a single value is given, it is mapped
121
+ to the bin index corresponding to that value. If a slice
122
+ is given, it is converted to a slice whose lower bound is
123
+ the index of the bin in which the slice's lower bound
124
+ falls, and whose upper bound is 1 greater than the index of
125
+ the bin in which the slice's upper bound falls. Steps are
126
+ not supported in slices.
127
+
128
+ Subclasses must override this method, but may chain to this
129
+ to handle slices:
130
+
131
+ def __getitem__(self, x):
132
+ if type(x) is slice:
133
+ return super(type(self), self).__getitem__(x)
134
+ # now handle non-slices ...
135
+ """
136
+ # assumes x is a slice. works with anything that defines
137
+ # .start, .stop and .step (but .step must be None).
138
+ if x.step is not None and x.step != 1:
139
+ raise NotImplementedError("step not supported: %s" % repr(x))
140
+ return slice(self[x.start] if x.start is not None else 0, self[x.stop] + 1 if x.stop is not None else len(self))
141
+
142
+ def __iter__(self):
143
+ """
144
+ If __iter__ does not exist, Python uses __getitem__ with
145
+ range(0) as input to define iteration. This is nonsensical
146
+ for bin objects, so explicitly unsupport iteration.
147
+ Subclasses do not need to override this method.
148
+ """
149
+ raise NotImplementedError
150
+
151
+ def lower(self):
152
+ """
153
+ Return an array containing the locations of the lower
154
+ boundaries of the bins. Subclasses should override this
155
+ method.
156
+ """
157
+ raise NotImplementedError
158
+
159
+ def centres(self):
160
+ """
161
+ Return an array containing the locations of the bin
162
+ centres. Subclasses should override this method.
163
+ """
164
+ raise NotImplementedError
165
+
166
+ def upper(self):
167
+ """
168
+ Return an array containing the locations of the upper
169
+ boundaries of the bins. Subclasses should override this
170
+ method.
171
+ """
172
+ raise NotImplementedError
173
+
174
+ #
175
+ # Sample from the binning
176
+ #
177
+
178
+ def randcoord(self, n = 1., domain = slice(None, None)):
179
+ """
180
+ Generator yielding a sequence of x, ln(P(x)) tuples where x
181
+ is a randomly-chosen co-ordinate and P(x) is the PDF from
182
+ which x has been drawn evaluated at x. Each co-ordinate is
183
+ drawn uniformly from within a bin, which has been drawn
184
+ from a distribution whose CDF goes as [bin index]^{n}. For
185
+ more information on how bins are drawn, see
186
+ lal.iterutils.randindex.
187
+
188
+ If a domain is given, the values returned fall within
189
+ [start, stop]. If start or stop is None, the corresponding
190
+ end of the binning is used. If start or stop does not
191
+ correspond exactly to a bin boundary, the probability of
192
+ drawing a value from that bin is unchanged, but the values
193
+ drawn from that bin will be restricted to the allowed part
194
+ of the bin (the PDF is adjusted to reflect this). No
195
+ values are returned from bins with infinite size (after
196
+ clipping them to the requested domain), and the PDF is
197
+ adjusted to reflect this.
198
+
199
+ Example:
200
+
201
+ >>> import math
202
+ >>> # natural log of 1/10
203
+ >>> print("%.15g" % math.log(1./10))
204
+ -2.30258509299405
205
+ >>> # linear bins spanning [0, 10]
206
+ >>> bins = LinearBins(0, 10, 5)
207
+ >>> # draw a random value, ln P(value) = ln 1/10
208
+ >>> next(bins.randcoord()) # doctest: +ELLIPSIS
209
+ (..., -2.3025850929940455)
210
+ >>> # binning with infinite boundaries
211
+ >>> bins = ATanBins(-1, +1, 4)
212
+ >>> # will ask for values in [0.5, +inf], i.e. the last two
213
+ >>> # bins, but values from final bin will be disallowed, so
214
+ >>> # return values will be uniform in part of the second
215
+ >>> # last bin, [0.5, 0.6366]
216
+ >>> print("%.15g" % math.log(1. / (bins.upper()[-2] - 0.5)))
217
+ 1.99055359585182
218
+ >>> next(bins.randcoord(domain = slice(0.5, None))) # doctest: +ELLIPSIS
219
+ (..., 1.9905535958518226)
220
+ >>> # things that aren't supported:
221
+ >>> # domain slice with a step
222
+ >>> next(LinearBins(0, 10, 1).randcoord(domain = slice(None, None, 2)))
223
+ Traceback (most recent call last):
224
+ ...
225
+ NotImplementedError: step not supported: slice(None, None, 2)
226
+
227
+ Subclasses should not override this method.
228
+ """
229
+ if len(self) < 1:
230
+ raise ValueError("empty binning")
231
+ if domain.step is not None:
232
+ raise NotImplementedError("step not supported: %s" % repr(domain))
233
+ # avoid symbol look-ups in the sampling loop
234
+ isinf = math.isinf
235
+ uniform = random.uniform
236
+ # determine boundaries and index range
237
+ l = self.lower()
238
+ u = self.upper()
239
+ lo, hi, _ = self[domain].indices(len(l))
240
+ if domain.start is not None:
241
+ assert l[lo] <= domain.start
242
+ l[lo] = domain.start
243
+ if domain.stop is not None:
244
+ assert u[hi - 1] >= domain.stop
245
+ u[hi - 1] = domain.stop
246
+ if isinf(u[lo] - l[lo]):
247
+ lo += 1
248
+ if isinf(u[hi - 1] - l[hi - 1]):
249
+ hi -= 1
250
+ if not lo < hi:
251
+ raise ValueError("slice too small")
252
+ # log() implicitly checks that the boundary adjustments
253
+ # above haven't made any bins <= 0 in size. converting
254
+ # everything to tuples makes the sampling loop faster
255
+ ln_dx = tuple(numpy.log(u - l))
256
+ l = tuple(l)
257
+ u = tuple(u)
258
+ # one last safety check
259
+ if any(map(isinf, ln_dx[lo:hi])):
260
+ raise ValueError("unavoidable infinite bin detected")
261
+ # generate samples
262
+ for i, ln_Pi in iterutils.randindex(lo, hi, n = n):
263
+ yield uniform(l[i], u[i]), ln_Pi - ln_dx[i]
264
+
265
+ #
266
+ # XML I/O related methods and data
267
+ #
268
+
269
+ @staticmethod
270
+ def xml_bins_name_enc(name, suffix = "pylal_rate_bins"):
271
+ """
272
+ For internal use by XML I/O code. Subclasses should not
273
+ override this method.
274
+ """
275
+ return "%s:%s" % (name, suffix)
276
+
277
+ @staticmethod
278
+ def xml_bins_name_dec(name, suffix = "pylal_rate_bins"):
279
+ """
280
+ For internal use by XML I/O code. Subclasses should not
281
+ override this method.
282
+ """
283
+ name = name.rsplit(":", 1)
284
+ if name[-1] != suffix:
285
+ raise ValueError(name)
286
+ return name[0]
287
+
288
+ @classmethod
289
+ def xml_bins_check(cls, elem, name):
290
+ """
291
+ For internal use by XML I/O code. Subclasses should not
292
+ override this method.
293
+ """
294
+ return elem.tagName == ligolw.Param.tagName and elem.hasAttribute("Name") and name == cls.xml_bins_name_dec(elem.Name)
295
+
296
+ def to_xml(self):
297
+ """
298
+ Construct a LIGO Light Weight XML representation of the
299
+ Bins instance. Subclasses must override this method to be
300
+ serializable to LIGO Light Weight XML, otherwise they need
301
+ not override it.
302
+ """
303
+ raise NotImplementedError
304
+
305
+ @classmethod
306
+ def from_xml(cls, xml):
307
+ """
308
+ From the XML Param element at xml, return the Bins object
309
+ it describes. Subclasses must override this method to be
310
+ de-serializable from LIGO Light Weight XML, otherwise they
311
+ need not override it.
312
+ """
313
+ raise NotImplementedError
314
+
315
+
316
+ class LoHiCountBins(Bins):
317
+ """
318
+ Base class to help implement binnings that can be defined by a
319
+ lower bound, an upper bound, and a count of bins. This is not a
320
+ binning.
321
+ """
322
+ def __init__(self, min, max, n):
323
+ """
324
+ The three arguments are the minimum and maximum of the
325
+ values spanned by the bins, and the number of bins to place
326
+ between them.
327
+ """
328
+ if not isinstance(n, int):
329
+ raise TypeError(n)
330
+ if n < 1:
331
+ raise ValueError(n)
332
+ if max <= min:
333
+ raise ValueError((min, max))
334
+ self.min = min
335
+ self.max = max
336
+ self.n = n
337
+
338
+ def __len__(self):
339
+ return self.n
340
+
341
+ def __eq__(self, other):
342
+ """
343
+ Two binnings are the same if they are instances of the same
344
+ class, have the same lower and upper bounds, and the same
345
+ count of bins.
346
+ """
347
+ return isinstance(other, type(self)) and (self.min, self.max, self.n) == (other.min, other.max, other.n)
348
+
349
+ #
350
+ # XML I/O related methods and data
351
+ #
352
+
353
+ def to_xml(self):
354
+ """
355
+ Construct a LIGO Light Weight XML representation of the
356
+ Bins instance. Subclasses must define the .xml_bins_name
357
+ class attribute.
358
+ """
359
+ return ligolw.Param.from_pyvalue(self.xml_bins_name_enc(self.xml_bins_name), "%s,%s,%s" % (ligolw_types.FormatFunc["real_8"](self.min), ligolw_types.FormatFunc["real_8"](self.max), ligolw_types.FormatFunc["int_8s"](self.n)))
360
+
361
+ @classmethod
362
+ def from_xml(cls, xml):
363
+ """
364
+ From the XML Param element at xml, return the Bins object
365
+ it describes. Subclasses must define the .xml_bins_name
366
+ class attribute.
367
+ """
368
+ if not cls.xml_bins_check(xml, cls.xml_bins_name):
369
+ raise ValueError("not a %s" % repr(cls))
370
+ lo, hi, n = xml.pcdata.split(",")
371
+ lo = ligolw_types.ToPyType["real_8"](lo)
372
+ hi = ligolw_types.ToPyType["real_8"](hi)
373
+ n = ligolw_types.ToPyType["int_8s"](n)
374
+ return cls(lo, hi, n)
375
+
376
+
377
+ class IrregularBins(Bins):
378
+ """
379
+ Bins with arbitrary, irregular spacing. We only require strict
380
+ monotonicity of the bin boundaries. N boundaries define N-1 bins.
381
+
382
+ Example:
383
+
384
+ >>> x = IrregularBins([0.0, 11.0, 15.0, numpy.inf])
385
+ >>> len(x)
386
+ 3
387
+ >>> x[1]
388
+ 0
389
+ >>> x[1.5]
390
+ 0
391
+ >>> x[13]
392
+ 1
393
+ >>> x[25]
394
+ 2
395
+ >>> x[4:17]
396
+ slice(0, 3, None)
397
+ >>> IrregularBins([0.0, 15.0, 11.0])
398
+ Traceback (most recent call last):
399
+ ...
400
+ ValueError: non-monotonic boundaries provided
401
+ >>> y = IrregularBins([0.0, 11.0, 15.0, numpy.inf])
402
+ >>> x == y
403
+ True
404
+ >>> import sys
405
+ >>> x.to_xml().write(sys.stdout) # doctest: +NORMALIZE_WHITESPACE
406
+ <Param Type="lstring" Name="irregularbins:pylal_rate_bins:param">0,11,15,inf</Param>
407
+ >>> IrregularBins.from_xml(x.to_xml()) == x
408
+ True
409
+ """
410
+ def __init__(self, boundaries):
411
+ """
412
+ Initialize a set of custom bins with the bin boundaries.
413
+ This includes all left edges plus the right edge. The
414
+ boundaries must be monotonic and there must be at least two
415
+ elements.
416
+ """
417
+ # check pre-conditions
418
+ if len(boundaries) < 2:
419
+ raise ValueError("less than two boundaries provided")
420
+ self.boundaries = numpy.array(boundaries)
421
+ if (self.boundaries[:-1] > self.boundaries[1:]).any():
422
+ raise ValueError("non-monotonic boundaries provided")
423
+ self.lo, self.hi = float(self.boundaries[0]), float(self.boundaries[-1])
424
+
425
+ def __eq__(self, other):
426
+ """
427
+ Two binnings are the same if they are instances of the same
428
+ class, and have the same boundaries.
429
+ """
430
+ return isinstance(other, type(self)) and (self.boundaries == other.boundaries).all()
431
+
432
+ def __len__(self):
433
+ return len(self.boundaries) - 1
434
+
435
+ def __getitem__(self, x):
436
+ # slice cannot be sub-classed so no need to use
437
+ # isinstance()
438
+ if type(x) is slice:
439
+ return super(IrregularBins, self).__getitem__(x)
440
+ if self.lo <= x < self.hi:
441
+ return self.boundaries.searchsorted(x, side = "right") - 1
442
+ # special measure-zero edge case
443
+ if x == self.hi:
444
+ return len(self.boundaries) - 2
445
+ raise IndexError(x)
446
+
447
+ def lower(self):
448
+ return self.boundaries[:-1]
449
+
450
+ def upper(self):
451
+ return self.boundaries[1:]
452
+
453
+ def centres(self):
454
+ return (self.lower() + self.upper()) / 2.0
455
+
456
+ #
457
+ # XML I/O related methods and data
458
+ #
459
+
460
+ xml_bins_name = "irregularbins"
461
+
462
+ def to_xml(self):
463
+ """
464
+ Construct a LIGO Light Weight XML representation of the
465
+ Bins instance.
466
+ """
467
+ return ligolw.Param.from_pyvalue(self.xml_bins_name_enc(self.xml_bins_name), ",".join(map(ligolw_types.FormatFunc["real_8"], self.boundaries)))
468
+
469
+ @classmethod
470
+ def from_xml(cls, xml):
471
+ """
472
+ From the XML Param element at xml, return the Bins object
473
+ it describes.
474
+ """
475
+ if not cls.xml_bins_check(xml, cls.xml_bins_name):
476
+ raise ValueError("not a %s" % repr(cls))
477
+ return cls(map(ligolw_types.ToPyType["real_8"], xml.pcdata.split(",")))
478
+
479
+
480
+ class LinearBins(LoHiCountBins):
481
+ """
482
+ Linearly-spaced bins. There are n bins of equal size, the first
483
+ bin starts on the lower bound and the last bin ends on the upper
484
+ bound inclusively.
485
+
486
+ Example:
487
+
488
+ >>> x = LinearBins(1.0, 25.0, 3)
489
+ >>> x.lower()
490
+ array([ 1., 9., 17.])
491
+ >>> x.upper()
492
+ array([ 9., 17., 25.])
493
+ >>> x.centres()
494
+ array([ 5., 13., 21.])
495
+ >>> x[1]
496
+ 0
497
+ >>> x[1.5]
498
+ 0
499
+ >>> x[10]
500
+ 1
501
+ >>> x[25]
502
+ 2
503
+ >>> x[0:27]
504
+ Traceback (most recent call last):
505
+ ...
506
+ IndexError: 0
507
+ >>> x[1:25]
508
+ slice(0, 3, None)
509
+ >>> x[:25]
510
+ slice(0, 3, None)
511
+ >>> x[10:16.9]
512
+ slice(1, 2, None)
513
+ >>> x[10:17]
514
+ slice(1, 3, None)
515
+ >>> x[10:]
516
+ slice(1, 3, None)
517
+ >>> import sys
518
+ >>> x.to_xml().write(sys.stdout) # doctest: +NORMALIZE_WHITESPACE
519
+ <Param Type="lstring" Name="linbins:pylal_rate_bins:param">1,25,3</Param>
520
+ >>> LinearBins.from_xml(x.to_xml()) == x
521
+ True
522
+ """
523
+ def __init__(self, min, max, n):
524
+ super(LinearBins, self).__init__(min, max, n)
525
+ self.delta = float(max - min) / n
526
+
527
+ def __getitem__(self, x):
528
+ # slice cannot be sub-classed so no need to use
529
+ # isinstance()
530
+ if type(x) is slice:
531
+ return super(LinearBins, self).__getitem__(x)
532
+ if self.min <= x < self.max:
533
+ return int(math.floor((x - self.min) / self.delta))
534
+ if x == self.max:
535
+ # special "measure zero" corner case
536
+ return len(self) - 1
537
+ raise IndexError(x)
538
+
539
+ def lower(self):
540
+ return numpy.linspace(self.min, self.max - self.delta, len(self))
541
+
542
+ def centres(self):
543
+ return numpy.linspace(self.min + self.delta / 2., self.max - self.delta / 2., len(self))
544
+
545
+ def upper(self):
546
+ return numpy.linspace(self.min + self.delta, self.max, len(self))
547
+
548
+ #
549
+ # XML I/O related methods and data
550
+ #
551
+
552
+ xml_bins_name = "linbins"
553
+
554
+
555
+ class LinearPlusOverflowBins(LoHiCountBins):
556
+ """
557
+ Linearly-spaced bins with overflow at the edges. There are n-2
558
+ bins of equal size. The bin 1 starts on the lower bound and bin
559
+ n-2 ends on the upper bound. Bins 0 and n-1 are overflow going
560
+ from -infinity to the lower bound and from the upper bound to
561
+ +infinity respectively. Must have n >= 3.
562
+
563
+ Example:
564
+
565
+ >>> x = LinearPlusOverflowBins(1.0, 25.0, 5)
566
+ >>> x.centres()
567
+ array([-inf, 5., 13., 21., inf])
568
+ >>> x.lower()
569
+ array([-inf, 1., 9., 17., 25.])
570
+ >>> x.upper()
571
+ array([ 1., 9., 17., 25., inf])
572
+ >>> x[float("-inf")]
573
+ 0
574
+ >>> x[0]
575
+ 0
576
+ >>> x[1]
577
+ 1
578
+ >>> x[10]
579
+ 2
580
+ >>> x[24.99999999]
581
+ 3
582
+ >>> x[25]
583
+ 4
584
+ >>> x[100]
585
+ 4
586
+ >>> x[float("+inf")]
587
+ 4
588
+ >>> x[float("-inf"):9]
589
+ slice(0, 3, None)
590
+ >>> x[9:float("+inf")]
591
+ slice(2, 5, None)
592
+ >>> import sys
593
+ >>> x.to_xml().write(sys.stdout) # doctest: +NORMALIZE_WHITESPACE
594
+ <Param Type="lstring" Name="linplusoverflowbins:pylal_rate_bins:param">1,25,5</Param>
595
+ >>> LinearPlusOverflowBins.from_xml(x.to_xml()) == x
596
+ True
597
+ """
598
+ def __init__(self, min, max, n):
599
+ if n < 3:
600
+ raise ValueError("n must be >= 3")
601
+ super(LinearPlusOverflowBins, self).__init__(min, max, n)
602
+ self.delta = float(max - min) / (n - 2)
603
+
604
+ def __getitem__(self, x):
605
+ # slice cannot be sub-classed so no need to use
606
+ # isinstance()
607
+ if type(x) is slice:
608
+ return super(LinearPlusOverflowBins, self).__getitem__(x)
609
+ if self.min <= x < self.max:
610
+ return int(math.floor((x - self.min) / self.delta)) + 1
611
+ if x >= self.max:
612
+ # +infinity overflow bin
613
+ return len(self) - 1
614
+ if x < self.min:
615
+ # -infinity overflow bin
616
+ return 0
617
+ raise IndexError(x)
618
+
619
+ def lower(self):
620
+ return numpy.concatenate((numpy.array([NegInf]), numpy.linspace(self.min, self.max - self.delta, len(self) - 1)))
621
+
622
+ def centres(self):
623
+ return numpy.concatenate((numpy.array([NegInf]), numpy.linspace(self.min + self.delta / 2., self.max - self.delta / 2., len(self) - 2), numpy.array([PosInf])))
624
+
625
+ def upper(self):
626
+ return numpy.concatenate((numpy.linspace(self.min + self.delta, self.max, len(self) - 1), numpy.array([PosInf])))
627
+
628
+ #
629
+ # XML I/O related methods and data
630
+ #
631
+
632
+ xml_bins_name = "linplusoverflowbins"
633
+
634
+
635
+ class LogarithmicBins(LoHiCountBins):
636
+ """
637
+ Logarithmically-spaced bins. There are n bins, each of whose upper
638
+ and lower bounds differ by the same factor. The first bin starts
639
+ on the lower bound, and the last bin ends on the upper bound
640
+ inclusively.
641
+
642
+ Example:
643
+
644
+ >>> x = LogarithmicBins(1.0, 25.0, 3)
645
+ >>> x[1]
646
+ 0
647
+ >>> x[5]
648
+ 1
649
+ >>> x[25]
650
+ 2
651
+ >>> import sys
652
+ >>> x.to_xml().write(sys.stdout) # doctest: +NORMALIZE_WHITESPACE
653
+ <Param Type="lstring" Name="logbins:pylal_rate_bins:param">1,25,3</Param>
654
+ >>> LogarithmicBins.from_xml(x.to_xml()) == x
655
+ True
656
+ """
657
+ def __init__(self, min, max, n):
658
+ super(LogarithmicBins, self).__init__(min, max, n)
659
+ self.logmin = math.log(min)
660
+ self.logmax = math.log(max)
661
+ self.delta = (self.logmax - self.logmin) / n
662
+
663
+ def __getitem__(self, x):
664
+ # slice cannot be sub-classed so no need to use
665
+ # isinstance()
666
+ if type(x) is slice:
667
+ return super(LogarithmicBins, self).__getitem__(x)
668
+ if self.min <= x < self.max:
669
+ return int(math.floor((math.log(x) - self.logmin) / self.delta))
670
+ if x == self.max:
671
+ # special "measure zero" corner case
672
+ return len(self) - 1
673
+ raise IndexError(x)
674
+
675
+ def lower(self):
676
+ return numpy.exp(numpy.linspace(self.logmin, self.logmax - self.delta, len(self)))
677
+
678
+ def centres(self):
679
+ return numpy.exp(numpy.linspace(self.logmin, self.logmax - self.delta, len(self)) + self.delta / 2.)
680
+
681
+ def upper(self):
682
+ return numpy.exp(numpy.linspace(self.logmin + self.delta, self.logmax, len(self)))
683
+
684
+ #
685
+ # XML I/O related methods and data
686
+ #
687
+
688
+ xml_bins_name = "logbins"
689
+
690
+
691
+ class LogarithmicPlusOverflowBins(LoHiCountBins):
692
+ """
693
+ Logarithmically-spaced bins plus one bin at each end that goes to
694
+ zero and positive infinity respectively. There are n-2 bins each
695
+ of whose upper and lower bounds differ by the same factor. Bin 1
696
+ starts on the lower bound, and bin n-2 ends on the upper bound
697
+ inclusively. Bins 0 and n-1 are overflow bins extending from 0 to
698
+ the lower bound and from the upper bound to +infinity respectively.
699
+ Must have n >= 3.
700
+
701
+ Example:
702
+
703
+ >>> x = LogarithmicPlusOverflowBins(1.0, 25.0, 5)
704
+ >>> x[0]
705
+ 0
706
+ >>> x[1]
707
+ 1
708
+ >>> x[5]
709
+ 2
710
+ >>> x[24.999]
711
+ 3
712
+ >>> x[25]
713
+ 4
714
+ >>> x[100]
715
+ 4
716
+ >>> x.lower()
717
+ array([ 0. , 1. , 2.92401774, 8.54987973, 25. ])
718
+ >>> x.upper()
719
+ array([ 1. , 2.92401774, 8.54987973, 25. , inf])
720
+ >>> x.centres()
721
+ array([ 0. , 1.70997595, 5. , 14.62008869, inf])
722
+ >>> import sys
723
+ >>> x.to_xml().write(sys.stdout) # doctest: +NORMALIZE_WHITESPACE
724
+ <Param Type="lstring" Name="logplusoverflowbins:pylal_rate_bins:param">1,25,5</Param>
725
+ >>> LogarithmicPlusOverflowBins.from_xml(x.to_xml()) == x
726
+ True
727
+ """
728
+ def __init__(self, min, max, n):
729
+ if n < 3:
730
+ raise ValueError("n must be >= 3")
731
+ super(LogarithmicPlusOverflowBins, self).__init__(min, max, n)
732
+ self.logmin = math.log(min)
733
+ self.logmax = math.log(max)
734
+ self.delta = (self.logmax - self.logmin) / (n - 2)
735
+
736
+ def __getitem__(self, x):
737
+ # slice cannot be sub-classed so no need to use
738
+ # isinstance()
739
+ if type(x) is slice:
740
+ return super(LogarithmicPlusOverflowBins, self).__getitem__(x)
741
+ if self.min <= x < self.max:
742
+ return 1 + int(math.floor((math.log(x) - self.logmin) / self.delta))
743
+ if x >= self.max:
744
+ # infinity overflow bin
745
+ return len(self) - 1
746
+ if x < self.min:
747
+ # zero overflow bin
748
+ return 0
749
+ raise IndexError(x)
750
+
751
+ def lower(self):
752
+ return numpy.concatenate((numpy.array([0.]), numpy.exp(numpy.linspace(self.logmin, self.logmax, len(self) - 1))))
753
+
754
+ def centres(self):
755
+ return numpy.concatenate((numpy.array([0.]), numpy.exp(numpy.linspace(self.logmin, self.logmax - self.delta, len(self) - 2) + self.delta / 2.), numpy.array([PosInf])))
756
+
757
+ def upper(self):
758
+ return numpy.concatenate((numpy.exp(numpy.linspace(self.logmin, self.logmax, len(self) - 1)), numpy.array([PosInf])))
759
+
760
+ #
761
+ # XML I/O related methods and data
762
+ #
763
+
764
+ xml_bins_name = "logplusoverflowbins"
765
+
766
+
767
+ class ATanBins(LoHiCountBins):
768
+ """
769
+ Bins spaced uniformly in tan^-1 x. Provides approximately linear
770
+ binning in the middle portion, with the bin density dropping
771
+ asymptotically to 0 as x goes to +/- \\infty. The min and max
772
+ parameters set the bounds of the region of approximately
773
+ uniformly-spaced bins. In a sense, these are where the roll-over
774
+ from uniformly-spaced bins to asymptotically diminishing bin
775
+ density occurs. There is a total of n bins.
776
+
777
+ Example:
778
+
779
+ >>> x = ATanBins(-1.0, +1.0, 11)
780
+ >>> x[float("-inf")]
781
+ 0
782
+ >>> x[0]
783
+ 5
784
+ >>> x[float("+inf")]
785
+ 10
786
+ >>> x.centres()
787
+ array([-4.42778777, -1.39400285, -0.73469838, -0.40913068, -0.18692843,
788
+ 0. , 0.18692843, 0.40913068, 0.73469838, 1.39400285,
789
+ 4.42778777])
790
+ >>> import sys
791
+ >>> x.to_xml().write(sys.stdout) # doctest: +NORMALIZE_WHITESPACE
792
+ <Param Type="lstring" Name="atanbins:pylal_rate_bins:param">-1,1,11</Param>
793
+ >>> ATanBins.from_xml(x.to_xml()) == x
794
+ True
795
+ """
796
+ def __init__(self, min, max, n):
797
+ super(ATanBins, self).__init__(min, max, n)
798
+ self.mid = (min + max) / 2.0
799
+ self.scale = math.pi / float(max - min)
800
+ self.delta = 1.0 / n
801
+
802
+ def __getitem__(self, x):
803
+ # slice cannot be sub-classed so no need to use
804
+ # isinstance()
805
+ if type(x) is slice:
806
+ return super(ATanBins, self).__getitem__(x)
807
+ # map to the domain [0, 1]
808
+ x = math.atan(float(x - self.mid) * self.scale) / math.pi + 0.5
809
+ if x < 1.:
810
+ return int(math.floor(x / self.delta))
811
+ # x == 1, special "measure zero" corner case
812
+ return len(self) - 1
813
+
814
+ def lower(self):
815
+ x = numpy.tan(numpy.linspace(-math.pi / 2., +math.pi / 2., len(self), endpoint = False)) / self.scale + self.mid
816
+ x[0] = NegInf
817
+ return x
818
+
819
+ def centres(self):
820
+ offset = 0.5 * math.pi * self.delta
821
+ return numpy.tan(numpy.linspace(-math.pi / 2. + offset, +math.pi / 2. + offset, len(self), endpoint = False)) / self.scale + self.mid
822
+
823
+ def upper(self):
824
+ offset = math.pi * self.delta
825
+ x = numpy.tan(numpy.linspace(-math.pi / 2. + offset, +math.pi / 2. + offset, len(self), endpoint = False)) / self.scale + self.mid
826
+ x[-1] = PosInf
827
+ return x
828
+
829
+ #
830
+ # XML I/O related methods and data
831
+ #
832
+
833
+ xml_bins_name = "atanbins"
834
+
835
+
836
+ class ATanLogarithmicBins(LoHiCountBins, IrregularBins):
837
+ """
838
+ Provides the same binning as the ATanBins class but in the
839
+ logarithm of the variable. The min and max parameters set the
840
+ bounds of the interval of approximately logarithmically-spaced
841
+ bins. In a sense, these are where the roll-over from
842
+ logarithmically-spaced bins to asymptotically diminishing bin
843
+ density occurs.
844
+
845
+ Example:
846
+
847
+ >>> x = ATanLogarithmicBins(+1.0, +1000.0, 11)
848
+ >>> x[0]
849
+ 0
850
+ >>> x[30]
851
+ 5
852
+ >>> x[float("+inf")]
853
+ 10
854
+ >>> x.centres()
855
+ array([ 7.21636246e-06, 2.56445876e-01, 2.50007148e+00,
856
+ 7.69668960e+00, 1.65808715e+01, 3.16227766e+01,
857
+ 6.03104608e+01, 1.29925988e+02, 3.99988563e+02,
858
+ 3.89945831e+03, 1.38573971e+08])
859
+ >>> import sys
860
+ >>> x.to_xml().write(sys.stdout) # doctest: +NORMALIZE_WHITESPACE
861
+ <Param Type="lstring" Name="atanlogbins:pylal_rate_bins:param">1,1000,11</Param>
862
+ >>> ATanLogarithmicBins.from_xml(x.to_xml()) == x
863
+ True
864
+
865
+ It is relatively easy to choose limits and a count of bins that
866
+ result in numerical overflows and underflows when computing bin
867
+ boundaries. When this happens, one or more bins at the ends of the
868
+ binning ends up with identical upper and lower boundaries (either
869
+ 0, or +inf), and this class behaves as though those bins simply
870
+ don't exist. That is, the actual number of bins can be less than
871
+ the number requested. len() returns the actual number of bins ---
872
+ how large an array the binning corresponds to.
873
+ """
874
+ def __init__(self, min, max, n):
875
+ if not isinstance(n, int):
876
+ raise TypeError(n)
877
+ if n < 1:
878
+ raise ValueError(n)
879
+ if max <= min:
880
+ raise ValueError((min, max))
881
+ self.mid = (math.log(min) + math.log(max)) / 2.0
882
+ self.scale = math.pi / (math.log(max) - math.log(min))
883
+ self.delta = 1.0 / n
884
+ boundaries = numpy.tan(-math.pi / 2 + math.pi * self.delta * numpy.arange(n)) / self.scale + self.mid
885
+ with numpy.errstate(over = "ignore"):
886
+ boundaries = numpy.exp(boundaries)
887
+ boundaries = numpy.hstack((boundaries, [PosInf, 0.]))
888
+ keepers = boundaries[:-1] != boundaries[1:]
889
+ IrregularBins.__init__(self, boundaries[:-1][keepers])
890
+ self.keepers = keepers[:-1]
891
+ self.min = min
892
+ self.max = max
893
+ self.n = n
894
+
895
+ __len__ = IrregularBins.__len__
896
+
897
+ def centres(self):
898
+ offset = 0.5 * math.pi * self.delta
899
+ centres = numpy.tan(numpy.linspace(-math.pi / 2. + offset, +math.pi / 2. + offset, self.n, endpoint = False)) / self.scale + self.mid
900
+ with numpy.errstate(over = "ignore"):
901
+ return numpy.exp(centres)[self.keepers]
902
+
903
+ #
904
+ # XML I/O related methods and data
905
+ #
906
+
907
+ xml_bins_name = "atanlogbins"
908
+
909
+
910
+ class Categories(Bins):
911
+ """
912
+ Categories is a many-to-one mapping from a value to an integer
913
+ category index. A value belongs to a category if it is contained
914
+ in the category's defining collection. If a value is contained in
915
+ more than one category's defining collection, it belongs to the
916
+ category with the smallest index. IndexError is raised if a value
917
+ is not contained in any category's defining collection.
918
+
919
+ Example with discrete values:
920
+
921
+ >>> categories = Categories([
922
+ ... set((frozenset(("H1", "L1")), frozenset(("H1", "V1")))),
923
+ ... set((frozenset(("H1", "L1", "V1")),))
924
+ ... ])
925
+ >>> categories[set(("H1", "L1"))]
926
+ 0
927
+ >>> categories[set(("H1", "V1"))]
928
+ 0
929
+ >>> categories[set(("H1", "L1", "V1"))]
930
+ 1
931
+
932
+ Example with continuous values:
933
+
934
+ >>> from igwn_segments import *
935
+ >>> categories = Categories([
936
+ ... segmentlist([segment(1, 3), segment(5, 7)]),
937
+ ... segmentlist([segment(0, PosInfinity)])
938
+ ... ])
939
+ >>> categories[2]
940
+ 0
941
+ >>> categories[4]
942
+ 1
943
+ >>> categories[-1]
944
+ Traceback (most recent call last):
945
+ ...
946
+ IndexError: -1
947
+
948
+ This last example demonstrates the behaviour when the intersection
949
+ of the categories is not the empty set.
950
+ """
951
+ def __init__(self, categories):
952
+ """
953
+ categories is an iterable of containers (objects that
954
+ support the "in" operator) defining the categories.
955
+ Objects will be mapped to the integer index of the
956
+ container that contains them.
957
+ """
958
+ # make immutable copy
959
+ self.containers = tuple(categories)
960
+
961
+ def __len__(self):
962
+ return len(self.containers)
963
+
964
+ def __getitem__(self, value):
965
+ """
966
+ Return i if value is contained in i-th container. If value
967
+ is not contained in any of the containers, raise an
968
+ IndexError. This is O(n).
969
+ """
970
+ for i, s in enumerate(self.containers):
971
+ if value in s:
972
+ return i
973
+ raise IndexError(value)
974
+
975
+ def __eq__(self, other):
976
+ return isinstance(other, type(self)) and self.containers == other.containers
977
+
978
+ def centres(self):
979
+ return self.containers
980
+
981
+ #
982
+ # XML I/O related methods and data
983
+ #
984
+
985
+ xml_bins_name = "categorybins"
986
+
987
+ def to_xml(self):
988
+ """
989
+ Construct a LIGO Light Weight XML representation of the
990
+ Bins instance.
991
+ """
992
+ return ligolw.Param.build(self.xml_bins_name_enc(self.xml_bins_name), "yaml", self.containers)
993
+
994
+ @classmethod
995
+ def from_xml(cls, xml):
996
+ """
997
+ From the XML Param element at xml, return the Bins object
998
+ it describes.
999
+ """
1000
+ if not cls.xml_bins_check(xml, cls.xml_bins_name):
1001
+ raise ValueError("not a %s" % repr(cls))
1002
+ return cls(xml.pcdata)
1003
+
1004
+
1005
+ class HashableBins(Categories):
1006
+ """
1007
+ Maps hashable objects (things that can be used as dictionary keys)
1008
+ to integers.
1009
+
1010
+ Example:
1011
+ >>> x = HashableBins([
1012
+ ... frozenset(("H1", "L1")),
1013
+ ... frozenset(("H1", "V1")),
1014
+ ... frozenset(("L1", "V1")),
1015
+ ... frozenset(("H1", "L1", "V1"))
1016
+ ... ])
1017
+ >>> x[frozenset(("H1", "L1"))]
1018
+ 0
1019
+ >>> x[set(("H1", "L1"))] # equal, but not hashable
1020
+ Traceback (most recent call last):
1021
+ ...
1022
+ IndexError: set(['H1', 'L1'])
1023
+ >>> x.centres()[2]
1024
+ frozenset(['V1', 'L1'])
1025
+ """
1026
+ def __init__(self, hashables):
1027
+ super(HashableBins, self).__init__(hashables)
1028
+ self.mapping = dict(zip(self.containers, range(len(self.containers))))
1029
+
1030
+ def __getitem__(self, value):
1031
+ try:
1032
+ return self.mapping[value]
1033
+ except (KeyError, TypeError):
1034
+ raise IndexError(value)
1035
+
1036
+ xml_bins_name = "hashablebins"
1037
+
1038
+
1039
+ class NDBins(tuple):
1040
+ """
1041
+ Multi-dimensional co-ordinate binning. An instance of this object
1042
+ is used to convert a tuple of co-ordinates into a tuple of bin
1043
+ indices. This can be used to allow the contents of an array object
1044
+ to be accessed with real-valued coordinates.
1045
+
1046
+ NDBins is a subclass of the tuple builtin, and is initialized with
1047
+ an iterable of instances of subclasses of Bins. Each Bins subclass
1048
+ instance describes the binning to apply in the corresponding
1049
+ co-ordinate direction, and the number of them sets the dimensions
1050
+ of the binning.
1051
+
1052
+ Example:
1053
+
1054
+ >>> x = NDBins((LinearBins(1, 25, 3), LogarithmicBins(1, 25, 3)))
1055
+ >>> x[1, 1]
1056
+ (0, 0)
1057
+ >>> x[1.5, 1]
1058
+ (0, 0)
1059
+ >>> x[10, 1]
1060
+ (1, 0)
1061
+ >>> x[1, 5]
1062
+ (0, 1)
1063
+ >>> x[1, 1:5]
1064
+ (0, slice(0, 2, None))
1065
+ >>> x.centres()
1066
+ (array([ 5., 13., 21.]), array([ 1.70997595, 5. , 14.62008869]))
1067
+ >>> y = NDBins((LinearBins(1, 25, 3), LogarithmicBins(1, 25, 3)))
1068
+ >>> x == y
1069
+ True
1070
+ >>> y = NDBins((LinearBins(1, 25, 4), LogarithmicBins(1, 25, 3)))
1071
+ >>> x == y
1072
+ False
1073
+ >>> y = NDBins((LogarithmicBins(1, 25, 3), LogarithmicBins(1, 25, 3)))
1074
+ >>> x == y
1075
+ False
1076
+ >>> from igwn_ligolw.ligolw import LIGO_LW
1077
+ >>> import sys
1078
+ >>> elem = x.to_xml(LIGO_LW())
1079
+ >>> elem.write(sys.stdout) # doctest: +NORMALIZE_WHITESPACE
1080
+ <LIGO_LW>
1081
+ <Param Type="lstring" Name="linbins:pylal_rate_bins:param">1,25,3</Param>
1082
+ <Param Type="lstring" Name="logbins:pylal_rate_bins:param">1,25,3</Param>
1083
+ </LIGO_LW>
1084
+ >>> NDBins.from_xml(elem) == x
1085
+ True
1086
+
1087
+ Note that the co-ordinates to be converted must be a tuple, even if
1088
+ it is only a 1-dimensional co-ordinate.
1089
+ """
1090
+ def __init__(self, binnings):
1091
+ self._getitems = tuple(binning.__getitem__ for binning in binnings)
1092
+ # instances cannot define a .__call__() attribute to make
1093
+ # themselves callable, Python always looks up .__call__()
1094
+ # on the class. so we define .__realcall__() here and then
1095
+ # have .__call__() chain to it. Python3 does not transfer
1096
+ # the current variable scope into exec() so we have to do
1097
+ # it for it ... whatever.
1098
+ define__realcall__ = """def __realcall__(self, %s):
1099
+ _getitems = self._getitems
1100
+ return %s""" % (", ".join("x%d" % i for i in range(len(binnings))), ", ".join("_getitems[%d](x%d)" % (i, i) for i in range(len(binnings))))
1101
+ l = {}
1102
+ exec(define__realcall__, globals(), l)
1103
+ __realcall__ = l["__realcall__"]
1104
+ self.__realcall__ = __realcall__.__get__(self)
1105
+
1106
+ def __getitem__(self, coords):
1107
+ """
1108
+ When coords is a tuple this is a synonym for self(*coords),
1109
+ otherwise coords is interpreted as an index into ourselves
1110
+ and the Bins object at that index is returned
1111
+
1112
+ Example:
1113
+
1114
+ >>> x = NDBins((LinearBins(1, 25, 3), LogarithmicBins(1, 25, 3)))
1115
+ >>> x[1, 1]
1116
+ (0, 0)
1117
+ >>> # slices can be given syntactically
1118
+ >>> x[10:12, 1]
1119
+ (slice(1, 2, None), 0)
1120
+ >>> type(x[1])
1121
+ <class 'lal.rate.LogarithmicBins'>
1122
+
1123
+ Note that if the argument is to be interpreted as a
1124
+ co-ordinate it must be a tuple even if it is only a
1125
+ 1-dimensional co-ordinate.
1126
+
1127
+ Example:
1128
+
1129
+ >>> x = NDBins((LinearBins(1, 25, 3),))
1130
+ >>> x[1,]
1131
+ (0,)
1132
+ """
1133
+ return self(*coords) if isinstance(coords, tuple) else tuple.__getitem__(self, coords)
1134
+
1135
+ def __call__(self, *coords):
1136
+ """
1137
+ Convert an N-dimensional co-ordinate to an N-tuple of bin
1138
+ indices using the Bins instances in this object. Calling
1139
+ the NDBins instance instead of using indexing (the "[]"
1140
+ operator) provides a more direct, faster, interface to the
1141
+ Bins instances contained herein, but slices cannot be given
1142
+ syntactically in the argument list
1143
+
1144
+ Example:
1145
+
1146
+ >>> x = NDBins((LinearBins(1, 25, 3), LogarithmicBins(1, 25, 3)))
1147
+ >>> x[1, 1] # access using index operator
1148
+ (0, 0)
1149
+ >>> x(1, 1) # access by calling
1150
+ (0, 0)
1151
+ >>> x = NDBins((LinearBins(1, 25, 3),))
1152
+ >>> x(1) # explicit tuples not required for 1D
1153
+ (0,)
1154
+ >>> x = NDBins((LinearBins(1, 25, 1000),))
1155
+ >>> x(slice(10, 12)) # slices (constructed manually)
1156
+ (slice(375, 459, None),)
1157
+ >>> x = NDBins((Categories([set(("Cow", "Chicken", "Goat")), set(("Tractor", "Plough")), set(("Barn", "House"))]),))
1158
+ >>> x("Cow")
1159
+ (0,)
1160
+
1161
+ Each co-ordinate can be anything the corresponding Bins
1162
+ instance will accept.
1163
+ """
1164
+ return self.__realcall__(*coords)
1165
+
1166
+ @property
1167
+ def shape(self):
1168
+ """
1169
+ Tuple of the number of bins along each dimension.
1170
+
1171
+ Example:
1172
+
1173
+ >>> NDBins((LinearBins(0, 6, 3), LinearBins(0, 10, 5))).shape
1174
+ (3, 5)
1175
+ """
1176
+ return tuple(len(b) for b in self)
1177
+
1178
+ def lower(self):
1179
+ """
1180
+ Return a tuple of arrays, where each array contains the
1181
+ locations of the lower boundaries of the bins in the
1182
+ corresponding dimension.
1183
+
1184
+ Example:
1185
+
1186
+ >>> NDBins((LinearBins(0, 6, 3), LinearBins(0, 10, 5))).lower()
1187
+ (array([ 0., 2., 4.]), array([ 0., 2., 4., 6., 8.]))
1188
+ """
1189
+ return tuple(b.lower() for b in self)
1190
+
1191
+ def centres(self):
1192
+ """
1193
+ Return a tuple of arrays, where each array contains the
1194
+ locations of the bin centres for the corresponding
1195
+ dimension.
1196
+
1197
+ Example:
1198
+
1199
+ >>> NDBins((LinearBins(0, 6, 3), LinearBins(0, 10, 5))).centres()
1200
+ (array([ 1., 3., 5.]), array([ 1., 3., 5., 7., 9.]))
1201
+ """
1202
+ return tuple(b.centres() for b in self)
1203
+
1204
+ def upper(self):
1205
+ """
1206
+ Return a tuple of arrays, where each array contains the
1207
+ locations of the upper boundaries of the bins in the
1208
+ corresponding dimension.
1209
+
1210
+ Example:
1211
+
1212
+ >>> NDBins((LinearBins(0, 6, 3), LinearBins(0, 10, 5))).upper()
1213
+ (array([ 2., 4., 6.]), array([ 2., 4., 6., 8., 10.]))
1214
+ """
1215
+ return tuple(b.upper() for b in self)
1216
+
1217
+ def volumes(self):
1218
+ """
1219
+ Return an n-dimensional array of the bin volumes.
1220
+
1221
+ Example:
1222
+
1223
+ >>> # 3x5 grid of bins, each 2 units by 2 units
1224
+ >>> x = NDBins((LinearBins(0, 6, 3), LinearBins(0, 10, 5)))
1225
+ >>> x.volumes()
1226
+ array([[ 4., 4., 4., 4., 4.],
1227
+ [ 4., 4., 4., 4., 4.],
1228
+ [ 4., 4., 4., 4., 4.]])
1229
+ """
1230
+ volumes = tuple(u - l for u, l in zip(self.upper(), self.lower()))
1231
+ if len(volumes) == 1:
1232
+ # 1D short-cut
1233
+ return volumes[0]
1234
+ try:
1235
+ return numpy.einsum(",".join("abcdefghijklmnopqrstuvwxyz"[:len(volumes)]), *volumes)
1236
+ except AttributeError:
1237
+ # numpy < 1.6
1238
+ result = reduce(numpy.outer, volumes)
1239
+ result.shape = tuple(len(v) for v in volumes)
1240
+ return result
1241
+
1242
+ def randcoord(self, ns = None, domain = None):
1243
+ """
1244
+ Generator yielding a sequence of (x0, x1, ...), ln(P(x0,
1245
+ x1, ...)) tuples where (x0, x1, ...) is a randomly-chosen
1246
+ co-ordinate in the N-dimensional binning and P(x0, x1, ...)
1247
+ is the PDF from which the co-ordinate tuple has been drawn
1248
+ evaluated at those co-ordinates. If ns is not None it must
1249
+ be a sequence of floats whose length matches the dimension
1250
+ of the binning. The floats will set the exponents, in
1251
+ order, of the CDFs for the generators used for each
1252
+ co-ordinate. If domain is not None it must be a sequence
1253
+ of slice objects whose length matches the dimension of the
1254
+ binning. The slice objects will be passed, in order, as
1255
+ the domain keyword argument to the .randcoord() method
1256
+ corresponding to each dimension. For more information on
1257
+ how each of the co-ordinates is drawn, see
1258
+ Bins.randcoord().
1259
+
1260
+ Example:
1261
+
1262
+ >>> binning = NDBins((LinearBins(0, 10, 5), LinearBins(0, 10, 5)))
1263
+ >>> coord = binning.randcoord()
1264
+ >>> next(coord) # doctest: +ELLIPSIS
1265
+ ((..., ...), -4.6051701859880909)
1266
+ """
1267
+ if ns is None:
1268
+ ns = (1.,) * len(self)
1269
+ if domain is None:
1270
+ domain = (slice(None, None),) * len(self)
1271
+ coordgens = tuple(iter(binning.randcoord(n, domain = d)) for binning, n, d in zip(self, ns, domain))
1272
+ while 1:
1273
+ seq = sum((next(coordgen) for coordgen in coordgens), ())
1274
+ yield seq[0::2], sum(seq[1::2])
1275
+
1276
+ #
1277
+ # XML I/O methods and data
1278
+ #
1279
+
1280
+ xml_bins_name_mapping = dict((cls.xml_bins_name, cls) for cls in (LinearBins, LinearPlusOverflowBins, LogarithmicBins, LogarithmicPlusOverflowBins, ATanBins, ATanLogarithmicBins, Categories, HashableBins))
1281
+ xml_bins_name_mapping.update(list(zip(xml_bins_name_mapping.values(), xml_bins_name_mapping.keys())))
1282
+
1283
+ def to_xml(self, elem):
1284
+ """
1285
+ Construct a LIGO Light Weight XML representation of the
1286
+ NDBins instance. The representation is an in-order list of
1287
+ Param elements, typically inserted inside a LIGO_LW
1288
+ element. The elem argument provides the XML element to
1289
+ which the Param elements should be appended as children.
1290
+
1291
+ NOTE: The decoding process will require a specific parent
1292
+ element to be provided, and all Param elements that are
1293
+ immediate children of that element and contain the correct
1294
+ suffix will be used to reconstruct the NDBins. At this
1295
+ time the suffix is undocumented, so to guarantee
1296
+ compatibility the Param elements should not be inserted
1297
+ into an element that might contain other, unrelated, Params
1298
+ among its immediate children.
1299
+ """
1300
+ for binning in self:
1301
+ elem.appendChild(binning.to_xml())
1302
+ return elem
1303
+
1304
+ @classmethod
1305
+ def from_xml(cls, xml):
1306
+ """
1307
+ From the XML document tree rooted at xml construct an
1308
+ return an NDBins object described by the Param elements
1309
+ therein. Note, the XML element must be the immediate
1310
+ parent of the Param elements describing the NDBins.
1311
+ """
1312
+ params = []
1313
+ for elem in xml.childNodes:
1314
+ if elem.tagName != ligolw.Param.tagName:
1315
+ continue
1316
+ try:
1317
+ Bins.xml_bins_name_dec(elem.Name)
1318
+ except ValueError:
1319
+ continue
1320
+ params.append(elem)
1321
+ if not params:
1322
+ raise ValueError("no Param elements found at '%s'" % repr(xml))
1323
+ return cls([cls.xml_bins_name_mapping[Bins.xml_bins_name_dec(elem.Name)].from_xml(elem) for elem in params])
1324
+
1325
+
1326
+ #
1327
+ # =============================================================================
1328
+ #
1329
+ # Segments and Bins
1330
+ #
1331
+ # =============================================================================
1332
+ #
1333
+
1334
+
1335
+ def bins_spanned(bins, seglist):
1336
+ """
1337
+ Input is a Bins subclass instance and a igwn_segments.segmentlist
1338
+ instance. The output is an array object the length of the binning,
1339
+ which each element in the array set to the interval in the
1340
+ corresponding bin spanned by the segment list.
1341
+
1342
+ Example:
1343
+
1344
+ >>> from igwn_segments import *
1345
+ >>> s = segmentlist([segment(1.5, 10.333), segment(15.8, 24)])
1346
+ >>> b = LinearBins(0, 30, 100)
1347
+ >>> bins_spanned(b, s)
1348
+ array([ 0. , 0. , 0. , 0. , 0. , 0.3 , 0.3 , 0.3 ,
1349
+ 0.3 , 0.3 , 0.3 , 0.3 , 0.3 , 0.3 , 0.3 , 0.3 ,
1350
+ 0.3 , 0.3 , 0.3 , 0.3 , 0.3 , 0.3 , 0.3 , 0.3 ,
1351
+ 0.3 , 0.3 , 0.3 , 0.3 , 0.3 , 0.3 , 0.3 , 0.3 ,
1352
+ 0.3 , 0.3 , 0.133, 0. , 0. , 0. , 0. , 0. ,
1353
+ 0. , 0. , 0. , 0. , 0. , 0. , 0. , 0. ,
1354
+ 0. , 0. , 0. , 0. , 0.1 , 0.3 , 0.3 , 0.3 ,
1355
+ 0.3 , 0.3 , 0.3 , 0.3 , 0.3 , 0.3 , 0.3 , 0.3 ,
1356
+ 0.3 , 0.3 , 0.3 , 0.3 , 0.3 , 0.3 , 0.3 , 0.3 ,
1357
+ 0.3 , 0.3 , 0.3 , 0.3 , 0.3 , 0.3 , 0.3 , 0.3 ,
1358
+ 0. , 0. , 0. , 0. , 0. , 0. , 0. , 0. ,
1359
+ 0. , 0. , 0. , 0. , 0. , 0. , 0. , 0. ,
1360
+ 0. , 0. , 0. , 0. ])
1361
+ """
1362
+ lower = bins.lower()
1363
+ upper = bins.upper()
1364
+ # performance improvement: pre-clip segments to the domain of the
1365
+ # binning
1366
+ seglist = seglist & segments.segmentlist([segments.segment(lower[0], upper[-1])])
1367
+ return numpy.fromiter((abs(seglist & segments.segmentlist([seg])) for seg in zip(lower, upper)), dtype = lower.dtype, count = len(bins))
1368
+
1369
+
1370
+ #
1371
+ # =============================================================================
1372
+ #
1373
+ # Binned Array
1374
+ #
1375
+ # =============================================================================
1376
+ #
1377
+
1378
+
1379
+ class BinnedArray(object):
1380
+ """
1381
+ A convenience wrapper, using the NDBins class to provide access to
1382
+ the elements of an array object. Technical reasons preclude
1383
+ providing a subclass of the array object, so the array data is made
1384
+ available as the "array" attribute of this class.
1385
+
1386
+ Examples:
1387
+
1388
+ Note that even for 1 dimensional arrays the index must be a tuple.
1389
+
1390
+ >>> x = BinnedArray(NDBins((LinearBins(0, 10, 5),)))
1391
+ >>> x.at_centres()
1392
+ array([ 0., 0., 0., 0., 0.])
1393
+ >>> x[0,] += 1
1394
+ >>> x[0.5,] += 1
1395
+ >>> x.at_centres()
1396
+ array([ 2., 0., 0., 0., 0.])
1397
+ >>> x.argmax()
1398
+ (1.0,)
1399
+
1400
+ Note the relationship between the binning limits, the bin centres,
1401
+ and the co-ordinates of the BinnedArray
1402
+
1403
+ >>> x = BinnedArray(NDBins((LinearBins(-0.5, 1.5, 2), LinearBins(-0.5, 1.5, 2))))
1404
+ >>> x.bins.centres()
1405
+ (array([ 0., 1.]), array([ 0., 1.]))
1406
+ >>> x[0, 0] = 0
1407
+ >>> x[0, 1] = 1
1408
+ >>> x[1, 0] = 2
1409
+ >>> x[1, 1] = 4
1410
+ >>> x.at_centres()
1411
+ array([[ 0., 1.],
1412
+ [ 2., 4.]])
1413
+ >>> x[0, 0]
1414
+ 0.0
1415
+ >>> x[0, 1]
1416
+ 1.0
1417
+ >>> x[1, 0]
1418
+ 2.0
1419
+ >>> x[1, 1]
1420
+ 4.0
1421
+ >>> x.argmin()
1422
+ (0.0, 0.0)
1423
+ >>> x.argmax()
1424
+ (1.0, 1.0)
1425
+
1426
+ A BinnedArray can be initialized from an existing array if the
1427
+ array's shape is the same as the binning's.
1428
+
1429
+ >>> import numpy
1430
+ >>> x = BinnedArray(NDBins((LinearBins(0, 10, 5),)), array = numpy.zeros((5,)))
1431
+ >>> x = BinnedArray(NDBins((LinearBins(0, 10, 5),)), array = numpy.zeros((5,1)))
1432
+ Traceback (most recent call last):
1433
+ ...
1434
+ ValueError: bins (shape = (5,)) and array (shape = (5, 1)), if supplied, must have the same shape
1435
+
1436
+ A BinnedArray can be serialized to LIGO Light Weight XML.
1437
+
1438
+ >>> import sys
1439
+ >>> x = BinnedArray(NDBins((LinearBins(-0.5, 1.5, 2), LinearBins(-0.5, 1.5, 2))))
1440
+ >>> elem = x.to_xml("test")
1441
+ >>> elem.write(sys.stdout) # doctest: +NORMALIZE_WHITESPACE
1442
+ <LIGO_LW Name="test:pylal_rate_binnedarray">
1443
+ <Param Type="lstring" Name="linbins:pylal_rate_bins:param">-0.5,1.5,2</Param>
1444
+ <Param Type="lstring" Name="linbins:pylal_rate_bins:param">-0.5,1.5,2</Param>
1445
+ <Array Type="real_8" Name="array:array">
1446
+ <Dim>2</Dim>
1447
+ <Dim>2</Dim>
1448
+ <Stream Delimiter=" " Type="Local">
1449
+ 0 0
1450
+ 0 0
1451
+ </Stream>
1452
+ </Array>
1453
+ </LIGO_LW>
1454
+ >>> y = BinnedArray.from_xml(elem, "test")
1455
+ >>> y.bins == x.bins
1456
+ True
1457
+ >>> (y.array == x.array).all()
1458
+ True
1459
+ """
1460
+ def __init__(self, bins, array = None, dtype = "double"):
1461
+ self.bins = bins
1462
+ if array is None:
1463
+ self.array = numpy.zeros(bins.shape, dtype = dtype)
1464
+ elif array.shape != bins.shape:
1465
+ raise ValueError("bins (shape = %s) and array (shape = %s), if supplied, must have the same shape" % (str(bins.shape), str(array.shape)))
1466
+ else:
1467
+ self.array = array
1468
+
1469
+ def __getitem__(self, coords):
1470
+ return self.array[self.bins(*coords)]
1471
+
1472
+ def __setitem__(self, coords, val):
1473
+ self.array[self.bins(*coords)] = val
1474
+
1475
+ def __len__(self):
1476
+ return len(self.array)
1477
+
1478
+ def __iadd__(self, other):
1479
+ """
1480
+ Add the contents of another BinnedArray object to this one.
1481
+ Both must have identical binnings.
1482
+
1483
+ Example:
1484
+
1485
+ >>> x = BinnedArray(NDBins((LinearBins(-0.5, 1.5, 2), LinearBins(-0.5, 1.5, 2))))
1486
+ >>> x[0, 0] = 0
1487
+ >>> x[0, 1] = 1
1488
+ >>> x[1, 0] = 2
1489
+ >>> x[1, 1] = 4
1490
+ >>> x.at_centres()
1491
+ array([[ 0., 1.],
1492
+ [ 2., 4.]])
1493
+ >>> x += x
1494
+ >>> x.at_centres()
1495
+ array([[ 0., 2.],
1496
+ [ 4., 8.]])
1497
+ """
1498
+ if self.bins != other.bins:
1499
+ raise TypeError("incompatible binning: %s" % repr(other))
1500
+ self.array += other.array
1501
+ return self
1502
+
1503
+ def __add__(self, other):
1504
+ """
1505
+ Add two BinnedArray objects together.
1506
+
1507
+ Example:
1508
+
1509
+ >>> x = BinnedArray(NDBins((LinearBins(-0.5, 1.5, 2), LinearBins(-0.5, 1.5, 2))))
1510
+ >>> x[0, 0] = 0
1511
+ >>> x[0, 1] = 1
1512
+ >>> x[1, 0] = 2
1513
+ >>> x[1, 1] = 4
1514
+ >>> x.at_centres()
1515
+ array([[ 0., 1.],
1516
+ [ 2., 4.]])
1517
+ >>> (x + x).at_centres()
1518
+ array([[ 0., 2.],
1519
+ [ 4., 8.]])
1520
+ """
1521
+ self = self.copy()
1522
+ self += other
1523
+ return self
1524
+
1525
+ def copy(self):
1526
+ """
1527
+ Return a copy of the BinnedArray. The .bins attribute is
1528
+ shared with the original.
1529
+ """
1530
+ return type(self)(self.bins, self.array.copy())
1531
+
1532
+ def centres(self):
1533
+ """
1534
+ Return a tuple of arrays containing the bin centres for
1535
+ each dimension.
1536
+ """
1537
+ return self.bins.centres()
1538
+
1539
+ def at_centres(self):
1540
+ """
1541
+ Return an array of the BinnedArray's value evaluated at the
1542
+ bin centres. In many cases this is simply a reference to
1543
+ the internal array object, but for subclasses that override
1544
+ item retrieval and assignment some additional work might be
1545
+ required to obtain this array. In those cases, this method
1546
+ is a convenience wrapper to avoid coding the evaluation
1547
+ logic in the calling code.
1548
+
1549
+ Because subclasses expect to be able to override this, in
1550
+ almost all cases calling code that wishes to access the
1551
+ values stored in the internal array directly should
1552
+ probably use this method to do so.
1553
+
1554
+ NOTE:
1555
+
1556
+ - The return value might be a newly-constructed object or a
1557
+ reference to an internal object.
1558
+ """
1559
+ return self.array
1560
+
1561
+ def argmin(self):
1562
+ """
1563
+ Return the co-ordinates of the bin centre containing the
1564
+ minimum value. Same as numpy.argmin(), converting the
1565
+ indexes to bin co-ordinates.
1566
+ """
1567
+ array = self.at_centres()
1568
+ return tuple(centres[index] for centres, index in zip(self.centres(), numpy.unravel_index(array.argmin(), array.shape)))
1569
+
1570
+ def argmax(self):
1571
+ """
1572
+ Return the co-ordinates of the bin centre containing the
1573
+ maximum value. Same as numpy.argmax(), converting the
1574
+ indexes to bin co-ordinates.
1575
+ """
1576
+ array = self.at_centres()
1577
+ return tuple(centres[index] for centres, index in zip(self.centres(), numpy.unravel_index(array.argmax(), array.shape)))
1578
+
1579
+ def to_xml(self, name):
1580
+ """
1581
+ Retrun an XML document tree describing a rate.BinnedArray
1582
+ object.
1583
+ """
1584
+ elem = ligolw.LIGO_LW()
1585
+ elem.Name = "%s:pylal_rate_binnedarray" % name
1586
+ self.bins.to_xml(elem)
1587
+ elem.appendChild(ligolw.Array.build("array", self.array))
1588
+ return elem
1589
+
1590
+ @classmethod
1591
+ def get_xml_root(cls, xml, name):
1592
+ name = "%s:pylal_rate_binnedarray" % name
1593
+ elem = [elem for elem in xml.getElementsByTagName(ligolw.LIGO_LW.tagName) if elem.hasAttribute("Name") and elem.Name == name]
1594
+ try:
1595
+ elem, = elem
1596
+ except ValueError:
1597
+ raise ValueError("XML tree at '%s' must contain exactly one '%s' LIGO_LW element" % (repr(xml), name))
1598
+ return elem
1599
+
1600
+ @classmethod
1601
+ def from_xml(cls, xml, name):
1602
+ """
1603
+ Search for the description of a rate.BinnedArray object
1604
+ named "name" in the XML document tree rooted at xml, and
1605
+ construct and return a new rate.BinnedArray object from the
1606
+ data contained therein.
1607
+
1608
+ NOTE: the .array attribute is a reference to the .array
1609
+ attribute of the XML element. Changes to the contents of
1610
+ the BinnedArray object affect the XML document tree.
1611
+ """
1612
+ elem = cls.get_xml_root(xml, name)
1613
+ self = cls(NDBins.from_xml(elem), array = ligolw.Array.get_array(elem, "array").array)
1614
+ # sanity check
1615
+ if self.bins.shape != self.array.shape:
1616
+ raise ValueError("'%s' binning shape does not match array shape: %s != %s" % (name, self.bins.shape, self.array.shape))
1617
+ # done
1618
+ return self
1619
+
1620
+
1621
+ #
1622
+ # =============================================================================
1623
+ #
1624
+ # Binned Array Interpolator
1625
+ #
1626
+ # =============================================================================
1627
+ #
1628
+
1629
+
1630
+ def InterpBinnedArray(binnedarray, fill_value = 0.0):
1631
+ """
1632
+ Wrapper constructing a scipy.interpolate interpolator from the
1633
+ contents of a BinnedArray. Only piecewise linear interpolators are
1634
+ supported. In 1 and 2 dimensions, scipy.interpolate.interp1d and
1635
+ .interp2d is used, respectively. In more than 2 dimensions
1636
+ scipy.interpolate.LinearNDInterpolator is used.
1637
+
1638
+ Example:
1639
+
1640
+ One dimension
1641
+
1642
+ >>> x = BinnedArray(NDBins((LinearBins(-0.5, 2.5, 3),)))
1643
+ >>> x[0,] = 0
1644
+ >>> x[1,] = 1
1645
+ >>> x[2,] = 3
1646
+ >>> y = InterpBinnedArray(x)
1647
+ >>> y(0)
1648
+ 0.0
1649
+ >>> y(1)
1650
+ 1.0
1651
+ >>> y(2)
1652
+ 3.0
1653
+ >>> y(0.5)
1654
+ 0.5
1655
+ >>> y(1.5)
1656
+ 2.0
1657
+
1658
+ Two dimensions
1659
+
1660
+ >>> x = BinnedArray(NDBins((LinearBins(-0.5, 2.5, 3), LinearBins(-0.5, 1.5, 2))))
1661
+ >>> x[0, 0] = 0
1662
+ >>> x[0, 1] = 1
1663
+ >>> x[1, 0] = 2
1664
+ >>> x[1, 1] = 4
1665
+ >>> x[2, 0] = 2
1666
+ >>> x[2, 1] = 4
1667
+ >>> y = InterpBinnedArray(x)
1668
+ >>> y(0, 0)
1669
+ 0.0
1670
+ >>> y(0, 1)
1671
+ 1.0
1672
+ >>> y(1, 0)
1673
+ 2.0
1674
+ >>> y(1, 1)
1675
+ 4.0
1676
+ >>> y(2, 0)
1677
+ 2.0
1678
+ >>> y(2, 1)
1679
+ 4.0
1680
+ >>> y(0, 0.25)
1681
+ 0.25
1682
+ >>> y(0, 0.75)
1683
+ 0.75
1684
+ >>> y(0.25, 0)
1685
+ 0.5
1686
+ >>> y(0.75, 0)
1687
+ 1.5
1688
+ >>> y(0.25, 1)
1689
+ 1.75
1690
+ >>> y(0.75, 1)
1691
+ 3.25
1692
+ >>> y(1, 0.25)
1693
+ 2.5
1694
+ >>> y(1, 0.75)
1695
+ 3.5
1696
+
1697
+ BUGS: Due to bugs in some versions of scipy and numpy, if an old
1698
+ version of scipy and/or numpy is detected this code falls back to
1699
+ home-grown piece-wise linear interpolator code for 1- and 2
1700
+ dimensions that is slow, and in 3- and higher dimensions the
1701
+ fall-back is to nearest-neighbour "interpolation".
1702
+ """
1703
+ # the upper and lower boundaries of the binnings are added as
1704
+ # additional co-ordinates with the array being assumed to equal
1705
+ # fill_value at those points. this solves the problem of providing
1706
+ # a valid function in the outer halves of the first and last bins.
1707
+
1708
+ # coords[0] = co-ordinates along 1st dimension,
1709
+ # coords[1] = co-ordinates along 2nd dimension,
1710
+ # ...
1711
+ coords = tuple(numpy.hstack((l[0], c, u[-1])) for l, c, u in zip(binnedarray.bins.lower(), binnedarray.bins.centres(), binnedarray.bins.upper()))
1712
+
1713
+ # pad the contents of the binned array with 1 element of fill_value
1714
+ # on each side in each dimension
1715
+ z = binnedarray.at_centres()
1716
+ z = numpy.pad(z, [(1, 1)] * z.ndim, mode = "constant", constant_values = [(fill_value, fill_value)] * z.ndim)
1717
+
1718
+ # if any co-ordinates are infinite, remove them. also remove
1719
+ # degenerate co-ordinates from ends
1720
+ slices = []
1721
+ for c in coords:
1722
+ finite_indexes, = numpy.isfinite(c).nonzero()
1723
+ assert len(finite_indexes) != 0
1724
+
1725
+ lo, hi = finite_indexes.min(), finite_indexes.max()
1726
+
1727
+ while lo < hi and c[lo + 1] == c[lo]:
1728
+ lo += 1
1729
+ while lo < hi and c[hi - 1] == c[hi]:
1730
+ hi -= 1
1731
+ assert lo < hi
1732
+
1733
+ slices.append(slice(lo, hi + 1))
1734
+ coords = tuple(c[s] for c, s in zip(coords, slices))
1735
+ z = z[tuple(slices)]
1736
+
1737
+ # build the interpolator from the co-ordinates and array data.
1738
+ # scipy/numpy interpolators return an array-like thing so we have
1739
+ # to wrap them, in turn, in a float cast
1740
+ if len(coords) == 1:
1741
+ try:
1742
+ interp1d
1743
+ except NameError:
1744
+ # FIXME: remove when we can rely on a new-enough scipy
1745
+ coords0 = coords[0]
1746
+ lo, hi = coords[0][0], coords[0][-1]
1747
+ with numpy.errstate(invalid = "ignore"):
1748
+ dz_over_dcoords0 = (z[1:] - z[:-1]) / (coords0[1:] - coords0[:-1])
1749
+ isinf = math.isinf
1750
+ def interp(x):
1751
+ if not lo < x < hi:
1752
+ return fill_value
1753
+ i = coords0.searchsorted(x) - 1
1754
+ if isinf(z[i]):
1755
+ return z[i]
1756
+ return z[i] + (x - coords0[i]) * dz_over_dcoords0[i]
1757
+ return interp
1758
+ interp = interp1d(coords[0], z, kind = "linear", copy = False, bounds_error = False, fill_value = fill_value)
1759
+ return lambda *coords: float(interp(*coords))
1760
+ elif len(coords) == 2:
1761
+ try:
1762
+ interp2d
1763
+ except NameError:
1764
+ # FIXME: remove when we can rely on a new-enough scipy
1765
+ coords0 = coords[0]
1766
+ coords1 = coords[1]
1767
+ lox, hix = coords0[0], coords0[-1]
1768
+ loy, hiy = coords1[0], coords1[-1]
1769
+ dcoords0 = coords0[1:] - coords0[:-1]
1770
+ dcoords1 = coords1[1:] - coords1[:-1]
1771
+ with numpy.errstate(invalid = "ignore"):
1772
+ dz0 = z[1:,:] - z[:-1,:]
1773
+ dz1 = z[:,1:] - z[:,:-1]
1774
+ isinf = math.isinf
1775
+ def interp(x, y):
1776
+ if not (lox < x < hix and loy < y < hiy):
1777
+ return fill_value
1778
+ i = coords0.searchsorted(x) - 1
1779
+ j = coords1.searchsorted(y) - 1
1780
+ dx = (x - coords0[i]) / dcoords0[i]
1781
+ dy = (y - coords1[j]) / dcoords1[j]
1782
+ if dx + dy <= 1.:
1783
+ if isinf(z[i, j]):
1784
+ return z[i, j]
1785
+ return z[i, j] + dx * dz0[i, j] + dy * dz1[i, j]
1786
+ if isinf(z[i + 1, j + 1]):
1787
+ return z[i + 1, j + 1]
1788
+ return z[i + 1, j + 1] + (1. - dx) * -dz0[i, j + 1] + (1. - dy) * -dz1[i + 1, j]
1789
+ return interp
1790
+ interp = interp2d(coords[0], coords[1], z.T, kind = "linear", copy = False, bounds_error = False, fill_value = fill_value)
1791
+ return lambda *coords: float(interp(*coords))
1792
+ else:
1793
+ try:
1794
+ LinearNDInterpolator
1795
+ except NameError:
1796
+ # FIXME: remove when we can rely on a new-enough scipy
1797
+ def interp(*coords):
1798
+ try:
1799
+ return binnedarray[coords]
1800
+ except IndexError:
1801
+ return fill_value
1802
+ return interp
1803
+ interp = LinearNDInterpolator(list(itertools.product(*coords)), z.flat, fill_value = fill_value)
1804
+ return lambda *coords: float(interp(*coords))
1805
+
1806
+
1807
+ #
1808
+ # =============================================================================
1809
+ #
1810
+ # BinnedDensity
1811
+ #
1812
+ # =============================================================================
1813
+ #
1814
+
1815
+
1816
+ class BinnedDensity(BinnedArray):
1817
+ """
1818
+ Variant of the BinnedArray type that interprets its contents as a
1819
+ density. When initialized, the volumes of the NDBins used to
1820
+ create the BinnedDensity are computed and stored in the .volume
1821
+ attribute. When a value is retrieved from a bin, the value
1822
+ reported is the value stored in the bin divided by the bin's
1823
+ volume. When a value is assigned to a bin, the value recorded is
1824
+ the assigned value multiplied by the bin's volume. The true values
1825
+ recorded in the bins can be accessed via the .count attribute,
1826
+ which is a BinnedArray object wrapping the same array and binning.
1827
+
1828
+ Because the internal array stores counts, not the densities, when
1829
+ the data in an instance of this class is processed with the
1830
+ filter_array() function the result is the density of smoothed
1831
+ counts, not the smoothed density. This is best illustrated with an
1832
+ example.
1833
+
1834
+ Example: linear bins
1835
+
1836
+ >>> # bins are 2 units, each
1837
+ >>> x = BinnedDensity(NDBins((LinearBins(0, 10, 5),)))
1838
+ >>> x.volume
1839
+ array([ 2., 2., 2., 2., 2.])
1840
+ >>> # set count at 5 to 1
1841
+ >>> x.count[5.0,] = 1
1842
+ >>> # internal array set to 1 in that bin
1843
+ >>> x.array
1844
+ array([ 0., 0., 1., 0., 0.])
1845
+ >>> # density reported is 0.5
1846
+ >>> print x[5.0,]
1847
+ 0.5
1848
+ >>> # convolve counts with 3-bin top hat window
1849
+ >>> filter_array(x.array, tophat_window(3))
1850
+ array([ 0. , 0.33333333, 0.33333333, 0.33333333, 0. ])
1851
+ >>> # density at 5 is now 1/6 counts / unit interval
1852
+ >>> print x[5.0,]
1853
+ 0.166666666667
1854
+ >>> # total count has been preserved
1855
+ >>> print x.array.sum()
1856
+ 1.0
1857
+
1858
+ Example: logarithmic bins
1859
+
1860
+ >>> # bins increase in size by a factor of 2, each
1861
+ >>> x = BinnedDensity(NDBins((LogarithmicBins(1, 32, 5),)))
1862
+ >>> x.volume
1863
+ array([ 1., 2., 4., 8., 16.])
1864
+ >>> # set count at 5 to 1
1865
+ >>> x.count[5.0,] = 1
1866
+ >>> # internal array set to 1 in that bin
1867
+ >>> x.array
1868
+ array([ 0., 0., 1., 0., 0.])
1869
+ >>> # density reported is 0.25
1870
+ >>> print x[5.0,]
1871
+ 0.25
1872
+ >>> # convolve counts with 3-bin top hat window
1873
+ >>> filter_array(x.array, tophat_window(3))
1874
+ array([ 0. , 0.33333333, 0.33333333, 0.33333333, 0. ])
1875
+ >>> # density at 5 is now 1/12 counts / unit interval
1876
+ >>> print x[5.0,]
1877
+ 0.0833333333333
1878
+ >>> # density is 1/6 in bin below
1879
+ >>> print x[3,]
1880
+ 0.166666666667
1881
+ >>> # and 1/24 in bin above
1882
+ >>> print x[10,]
1883
+ 0.0416666666667
1884
+ >>> # total count has been preserved
1885
+ >>> print x.array.sum()
1886
+ 1.0
1887
+
1888
+ Explanation. In the linear case there are five bins spanning the
1889
+ interval [0, 10], making each bin 2 "units" in size. A single
1890
+ count is placed at 5.0, which is bin number 2. The averaging
1891
+ filter is a top-hat window 3 bins wide. The single count in bin
1892
+ #2, when averaged over the three bins around it, becomes an average
1893
+ of 1/3 count per bin, each of which is 2 units in size, so the
1894
+ average density is 1/6 events / unit. The count has been spread
1895
+ out over several bins but the integral of the density, the total
1896
+ count, is unchanged. The logarithmic case is identical but because
1897
+ the bin sizes are non-uniform, when the single count is spread
1898
+ across the three bins the density is non-uniform. The integral is
1899
+ still preserved.
1900
+
1901
+ Some binnings have infinite-sized bins. For such bins, the counts
1902
+ may be manipulated directly, as usual, but for all finite counts a
1903
+ density of 0 will be reported for those bins (and NaN for infinite
1904
+ counts), and ValueError will be raised if an attempt is made to
1905
+ assign a density to those bins.
1906
+
1907
+ NOTES:
1908
+
1909
+ - While it is technically possible to modify the binning parameters
1910
+ after creating an instance of this class, the steps required to
1911
+ bring all internal data back into consistency following such a
1912
+ change are undocumented. One should consider the metadata
1913
+ carried by these objects to be immutable.
1914
+ """
1915
+ def __init__(self, *args, **kwargs):
1916
+ super(BinnedDensity, self).__init__(*args, **kwargs)
1917
+ self.count = BinnedArray(self.bins, array = self.array)
1918
+ self.volume = self.bins.volumes()
1919
+
1920
+ def __getitem__(self, coords):
1921
+ coords = self.bins(*coords)
1922
+ return self.array[coords] / self.volume[coords]
1923
+
1924
+ def __setitem__(self, coords, val):
1925
+ coords = self.bins(*coords)
1926
+ vol = self.volume[coords]
1927
+ if numpy.isinf(vol).any():
1928
+ raise ValueError("cannot assign density values to infinite-volume bins, try assigning a count instead")
1929
+ self.array[coords] = val * vol
1930
+
1931
+ def at_centres(self):
1932
+ return self.array / self.volume
1933
+
1934
+ def marginalize(self, dim):
1935
+ """
1936
+ Return a new BinnedDensity object containing the density
1937
+ integrated over dimension dim.
1938
+
1939
+ Example:
1940
+
1941
+ >>> # 5x5 mesh of bins, each with volume = 4
1942
+ >>> x = BinnedDensity(NDBins((LinearBins(0, 10, 5), LinearBins(0, 10, 5))))
1943
+ >>> # set count at 5,5 to 1
1944
+ >>> x.count[5.0, 5.0] = 1
1945
+ >>> # density in central bin is 1/4
1946
+ >>> x.at_centres()
1947
+ array([[ 0. , 0. , 0. , 0. , 0. ],
1948
+ [ 0. , 0. , 0. , 0. , 0. ],
1949
+ [ 0. , 0. , 0.25, 0. , 0. ],
1950
+ [ 0. , 0. , 0. , 0. , 0. ],
1951
+ [ 0. , 0. , 0. , 0. , 0. ]])
1952
+ >>> # convolve counts with 3-bin top-hat window
1953
+ >>> filter_array(x.array, tophat_window(3, 3))
1954
+ array([[ 0. , 0. , 0. , 0. , 0. ],
1955
+ [ 0. , 0.11111111, 0.11111111, 0.11111111, 0. ],
1956
+ [ 0. , 0.11111111, 0.11111111, 0.11111111, 0. ],
1957
+ [ 0. , 0.11111111, 0.11111111, 0.11111111, 0. ],
1958
+ [ 0. , 0. , 0. , 0. , 0. ]])
1959
+ >>> # density is now 1/(4 * 9) = 1/36 in 9 central bins
1960
+ >>> x.at_centres()
1961
+ array([[ 0. , 0. , 0. , 0. , 0. ],
1962
+ [ 0. , 0.02777778, 0.02777778, 0.02777778, 0. ],
1963
+ [ 0. , 0.02777778, 0.02777778, 0.02777778, 0. ],
1964
+ [ 0. , 0.02777778, 0.02777778, 0.02777778, 0. ],
1965
+ [ 0. , 0. , 0. , 0. , 0. ]])
1966
+ >>> # densities still sum (not integrate) to 1/4
1967
+ >>> x.at_centres().sum()
1968
+ 0.25
1969
+ >>> # integrate over dimension 1
1970
+ >>> x = x.marginalize(1)
1971
+ >>> # bin volumes are now 2
1972
+ >>> # densities in 3 central bins are = 1/(2 * 3) = 1/6
1973
+ >>> x.at_centres()
1974
+ array([ 0. , 0.16666667, 0.16666667, 0.16666667, 0. ])
1975
+ >>> # densities sum (not integrate) to 1/2
1976
+ >>> x.at_centres().sum()
1977
+ 0.5
1978
+ """
1979
+ return type(self)(NDBins(self.bins[:dim] + self.bins[dim+1:]), self.array.sum(axis = dim))
1980
+
1981
+
1982
+ #
1983
+ # A discretely sampled PDF.
1984
+ #
1985
+
1986
+
1987
+ class BinnedLnPDF(BinnedDensity):
1988
+ """
1989
+ Variant of the BinnedDensity class that (i) tracks a normalization
1990
+ which it uses to rescale the reported density so that its integral
1991
+ is one, and (ii) reports the natural logarithm of that normalized
1992
+ density.
1993
+
1994
+ The .normalize() method needs to be invoked after any manipulation
1995
+ of the contents of the array before the results of .__getitem__()
1996
+ are meaningful.
1997
+
1998
+ How the normalization is tracked should be assumed to be
1999
+ undocumented. In this class the .norm attribute contains the
2000
+ natural log of the sum of the counts in all bins and this value is
2001
+ subtracted from the natural log of the (unnormalized) density in
2002
+ the .__getitem__() method, but subclasses are free to implement
2003
+ whatever unique mechanism is appropriate for themselves.
2004
+
2005
+ As with the BinnedDensity class, the internal array contains counts
2006
+ (not densities, nor natural logarithms of densities), and the
2007
+ .count attribute continues to be a BinnedArray interface to those
2008
+ counts. The intention is for the counts themselves to provide an
2009
+ additional degree of freedom apart from the normalized density.
2010
+ For example, see the .__iadd__() method where it is assumed that
2011
+ the total count encodes a relative weight to be used when
2012
+ marginalizing over two PDFs.
2013
+
2014
+ Example:
2015
+
2016
+ >>> # 5x5 mesh of bins each with volume = 4
2017
+ >>> x = BinnedLnPDF(NDBins((LinearBins(0, 10, 5), LinearBins(0, 10, 5))))
2018
+ >>> # set count at 5,5 to 36 and normalize
2019
+ >>> x.count[5.0, 5.0] = 36
2020
+ >>> x.normalize()
2021
+ >>> # log probability density = ln 1/4 = -1.3862943611198906
2022
+ >>> x.at_centres()
2023
+ array([[ -inf, -inf, -inf, -inf, -inf],
2024
+ [ -inf, -inf, -inf, -inf, -inf],
2025
+ [ -inf, -inf, -1.38629436, -inf, -inf],
2026
+ [ -inf, -inf, -inf, -inf, -inf],
2027
+ [ -inf, -inf, -inf, -inf, -inf]])
2028
+ >>> # convolve with 3x3 top-hat window. in general one must renormalize after this, but we'll skip that here because the demo is constructed so as to not need it
2029
+ >>> filter_array(x.array, tophat_window(3, 3))
2030
+ array([[ 0., 0., 0., 0., 0.],
2031
+ [ 0., 4., 4., 4., 0.],
2032
+ [ 0., 4., 4., 4., 0.],
2033
+ [ 0., 4., 4., 4., 0.],
2034
+ [ 0., 0., 0., 0., 0.]])
2035
+ >>> # ln probability density = ln 1/(4 * 9) = -3.58351893845611
2036
+ >>> x.at_centres()
2037
+ array([[ -inf, -inf, -inf, -inf, -inf],
2038
+ [ -inf, -3.58351894, -3.58351894, -3.58351894, -inf],
2039
+ [ -inf, -3.58351894, -3.58351894, -3.58351894, -inf],
2040
+ [ -inf, -3.58351894, -3.58351894, -3.58351894, -inf],
2041
+ [ -inf, -inf, -inf, -inf, -inf]])
2042
+ >>> # .marginzlize() preserves normalization
2043
+ >>> y = x.marginalize(1)
2044
+ >>> y.count.at_centres()
2045
+ array([ 0., 12., 12., 12., 0.])
2046
+ >>> # ln probability density = ln 1/(2 * 3) = -1.791759469228055
2047
+ >>> y.at_centres()
2048
+ array([ -inf, -1.79175947, -1.79175947, -1.79175947, -inf])
2049
+ >>> # assuming \\sqrt{N} counting fluctuations, compute the fractional uncertainty
2050
+ >>> import numpy
2051
+ >>> d = BinnedArray(x.bins, 1. / numpy.sqrt(x.count.at_centres()))
2052
+ >>> d.at_centres()
2053
+ array([[ inf, inf, inf, inf, inf],
2054
+ [ inf, 0.5, 0.5, 0.5, inf],
2055
+ [ inf, 0.5, 0.5, 0.5, inf],
2056
+ [ inf, 0.5, 0.5, 0.5, inf],
2057
+ [ inf, inf, inf, inf, inf]])
2058
+ """
2059
+ def __init__(self, *args, **kwargs):
2060
+ super(BinnedLnPDF, self).__init__(*args, **kwargs)
2061
+ self.normalize()
2062
+
2063
+ def __getitem__(self, coords):
2064
+ return numpy.log(super(BinnedLnPDF, self).__getitem__(coords)) - self.norm
2065
+
2066
+ def __setitem__(self, coords, val):
2067
+ #
2068
+ # the relationship between the density, p, the
2069
+ # volume, Delta, the count, x, and the overall
2070
+ # normalization, N, for a bin i is
2071
+ #
2072
+ # p_i = x_i / (Delta_i * N)
2073
+ #
2074
+ # where N = sum_j x_j, and 0 <= p_i * Delta_i <= 1.
2075
+ #
2076
+ # to maintain the requirement that the density integrate to
2077
+ # 1, it is not possible to change the density in one bin
2078
+ # without changing the densities in all other bins.
2079
+ # because there is no unique way to assign new densities to
2080
+ # all other bins that preserves the normalization invariant
2081
+ # there is an ambiguity in how to implement the assignment
2082
+ # operation. instead of choosing one, we elect to forbid
2083
+ # this operation.
2084
+ #
2085
+ # one interpretation could be to require the counts in all
2086
+ # other bins to be preserved, and solve for the new count
2087
+ # for the bin in question (and new total count). because
2088
+ # the counts in other bins are held constant the likelihood
2089
+ # ratios among them are preserved.
2090
+ #
2091
+ # solving for x_i,
2092
+ #
2093
+ # p_i * Delta_i
2094
+ # x_i = ----------------- sum_(j != i) x_j.
2095
+ # 1 - p_i * Delta_i
2096
+ #
2097
+ # the normalization would then need to be recomputed given
2098
+ # the new count for bin i. forbidden cases include:
2099
+ # infinite bin size, total count is initially 0,
2100
+ # p_i*Delta_i = 1 unless bin i is the only non-zero bin to
2101
+ # begin with.
2102
+ #
2103
+ # another interpretation could be to require the total
2104
+ # count to be preserved and also the likelihood ratios
2105
+ # among all other bins. because the total count is being
2106
+ # preserved, the new x_i can be obtained immediately as
2107
+ #
2108
+ # x_i' = N * p_i * Delta_i
2109
+ #
2110
+ # the counts in all other bins are obtained by rescaling by
2111
+ # the after-to-before ratio of the non-bin-i count.
2112
+ #
2113
+ # x_(j != i) = x_(j != i) * (N - x_i') / (N - x_i)
2114
+ #
2115
+ # because they are scaled by a common factor, the ratios
2116
+ # between them are preserved. forbidden cases include:
2117
+ # infinite bin size, total count is initially 0.
2118
+ #
2119
+ raise NotImplementedError("item assignment operation not defined. assign to .count then invoke .normalize()")
2120
+
2121
+ def mkinterp(self):
2122
+ """
2123
+ Return an interpolator to evaluate the density as a smooth
2124
+ function of co-ordinates. If the density has not been
2125
+ normalized the interpolator's behaviour is undefined.
2126
+
2127
+ NOTE: the interpolator is the InterpBinnedArray object
2128
+ which might have limitations in 3 or more dimensions. See
2129
+ its documentation for more information.
2130
+
2131
+ NOTE: in the future this is likely to be replaced with
2132
+ some sort of internal mechanism.
2133
+
2134
+ Example:
2135
+
2136
+ >>> # 5-bin linear mesh of bins each with volume = 2
2137
+ >>> x = BinnedLnPDF(NDBins((LinearBins(0, 10, 5), )))
2138
+ >>> # set some counts and normalize
2139
+ >>> x.count[3,] = x.count[7,] = 1
2140
+ >>> x.count[5,] = 2
2141
+ >>> x.normalize()
2142
+ >>> x.count.at_centres()
2143
+ array([ 0., 1., 2., 1., 0.])
2144
+ >>> x.at_centres()
2145
+ array([ -inf, -2.07944154, -1.38629436, -2.07944154, -inf])
2146
+ >>> # construct interpolator object
2147
+ >>> x = x.mkinterp()
2148
+ >>> # log(P) is interpolated linearly, so it can be counter-intuitive where the density drops to 0 in neighbouring bins
2149
+ >>> x(3)
2150
+ -inf
2151
+ >>> # otherwise behaviour is as expected
2152
+ >>> x(4)
2153
+ -1.732867951399863
2154
+ >>> x(4.5)
2155
+ -1.5595811562598769
2156
+ >>> x(5)
2157
+ -1.3862943611198906
2158
+ """
2159
+ return InterpBinnedArray(self)
2160
+
2161
+ def at_centres(self):
2162
+ with numpy.errstate(divide = "ignore", invalid = "ignore"):
2163
+ return numpy.log(super(BinnedLnPDF, self).at_centres()) - self.norm
2164
+
2165
+ def marginalize(self, dim):
2166
+ new = super(BinnedLnPDF, self).marginalize(dim)
2167
+ new.norm = self.norm
2168
+ return new
2169
+
2170
+ def __iadd__(self, other):
2171
+ """
2172
+ Adds the counts array and normalization of other to self.
2173
+ If the original two PDFs were normalized then the result is
2174
+ also normalized, otherwise .normalize() needs to be invoked
2175
+ to normalize the result. Once normalized, the result is
2176
+ the PDF marginalized over the two original PDFs (the sum of
2177
+ the two PDFs weighted by the relative total frequency of
2178
+ events in each).
2179
+
2180
+ Example:
2181
+
2182
+ >>> # 5-bin linear mesh of bins each with volume = 2
2183
+ >>> x = BinnedLnPDF(NDBins((LinearBins(0, 10, 5), )))
2184
+ >>> y = BinnedLnPDF(NDBins((LinearBins(0, 10, 5), )))
2185
+ >>> x.count[5,] = 2
2186
+ >>> y.count[3,] = 2
2187
+ >>> x.normalize()
2188
+ >>> y.normalize()
2189
+ >>> x.at_centres()
2190
+ array([ -inf, -inf, -0.69314718, -inf, -inf])
2191
+ >>> x += y
2192
+ >>> x.at_centres()
2193
+ array([ -inf, -1.38629436, -1.38629436, -inf, -inf])
2194
+ """
2195
+ super(BinnedLnPDF, self).__iadd__(other)
2196
+ # how to add two numbers when all you know are their
2197
+ # logarithms:
2198
+ #
2199
+ # c = a + b
2200
+ #
2201
+ # if b is smaller than a:
2202
+ #
2203
+ # c = a (1 + b/a)
2204
+ # log c = log a + log1p(b / a)
2205
+ # log c = log a + log1p(exp(log b - log a))
2206
+ #
2207
+ # otherwise, if a is smaller than b, do the same but swap a
2208
+ # and b.
2209
+ if self.norm >= other.norm:
2210
+ self.norm += math.log1p(math.exp(other.norm - self.norm))
2211
+ else:
2212
+ self.norm = other.norm + math.log1p(math.exp(self.norm - other.norm))
2213
+ return self
2214
+
2215
+ def __add__(self, other):
2216
+ self = super(BinnedLnPDF, self).__add__(other)
2217
+ self.normalize()
2218
+ return self
2219
+
2220
+ def copy(self):
2221
+ new = super(BinnedLnPDF, self).copy()
2222
+ new.norm = self.norm
2223
+ return new
2224
+
2225
+ def normalize(self):
2226
+ """
2227
+ Updates the internal normalization. Subclasses override
2228
+ this with custom normalization mechanisms if required.
2229
+
2230
+ Note that counts contained in infinite-sized bins are
2231
+ included in the normalization. In this way the relative
2232
+ frequency with which counts occur in those bins is
2233
+ accounted for in the normalization although the density
2234
+ reported for those bins will be 0.
2235
+ """
2236
+ self.norm = self.array.sum()
2237
+ assert self.norm >= 0. or math.isnan(self.norm)
2238
+ self.norm = math.log(self.norm) if self.norm != 0. else NegInf
2239
+
2240
+ def to_xml(self, *args, **kwargs):
2241
+ elem = super(BinnedLnPDF, self).to_xml(*args, **kwargs)
2242
+ elem.appendChild(ligolw.Param.from_pyvalue("norm", self.norm))
2243
+ return elem
2244
+
2245
+ @classmethod
2246
+ def from_xml(cls, xml, name):
2247
+ elem = cls.get_xml_root(xml, name)
2248
+ self = super(BinnedLnPDF, cls).from_xml(elem, name)
2249
+ self.norm = ligolw.Param.get_param(elem, "norm").value
2250
+ return self
2251
+
2252
+
2253
+ #
2254
+ # =============================================================================
2255
+ #
2256
+ # Windows
2257
+ #
2258
+ # =============================================================================
2259
+ #
2260
+
2261
+
2262
+ def gaussian_window(*bins, **kwargs):
2263
+ """
2264
+ Generate a normalized (integral = 1) Gaussian window in N
2265
+ dimensions. The bins parameters set the width of the window in bin
2266
+ counts in each dimension. The optional keyword argument sigma,
2267
+ which defaults to 10, sets the size of the array in all dimensions
2268
+ in units of the width in each dimension. The sizes are adjusted so
2269
+ that the array has an odd number of samples in each dimension, and
2270
+ the Gaussian is peaked on the middle sample.
2271
+
2272
+ Example:
2273
+
2274
+ >>> # 2D window with width of 1.5 bins in first dimension,
2275
+ >>> # 1 bin in second dimension, 3 widths long (rounded to odd
2276
+ >>> # integer = 5 x 3 bins) in each dimension
2277
+ >>> gaussian_window(1.5, 1, sigma = 3)
2278
+ array([[ 0.00161887, 0.01196189, 0.00161887],
2279
+ [ 0.02329859, 0.17215456, 0.02329859],
2280
+ [ 0.05667207, 0.41875314, 0.05667207],
2281
+ [ 0.02329859, 0.17215456, 0.02329859],
2282
+ [ 0.00161887, 0.01196189, 0.00161887]])
2283
+ """
2284
+ if not bins:
2285
+ raise ValueError("function requires at least 1 width")
2286
+ if min(bins) < 0.:
2287
+ raise ValueError("widths must be non-negative, got %s" % str(bins))
2288
+ sigma = kwargs.pop("sigma", 10)
2289
+ if kwargs:
2290
+ raise ValueError("unrecognized keyword argument(s): %s" % ",".join(kwargs))
2291
+ windows = []
2292
+ for b in bins:
2293
+ l = int(math.floor(sigma * b / 2.0)) * 2
2294
+ w = lal.CreateGaussREAL8Window(l + 1, l / float(b) if b else PosInf)
2295
+ windows.append(w.data.data / w.sum)
2296
+ if len(windows) == 1:
2297
+ # 1D short-cut
2298
+ return windows[0]
2299
+ try:
2300
+ # only works upto 26 dimensions, but that's 2 trillion bins
2301
+ # if there are just 3 bins along each side, so it's
2302
+ # unlikely to be a practical limitation; for a while at
2303
+ # least
2304
+ assert len(windows) <= 26
2305
+ return numpy.einsum(",".join("abcdefghijklmnopqrstuvwxyz"[:len(windows)]), *windows)
2306
+ except AttributeError:
2307
+ # numpy < 1.6
2308
+ window = reduce(numpy.outer, windows)
2309
+ window.shape = tuple(len(w) for w in windows)
2310
+ return window
2311
+
2312
+
2313
+ def tophat_window(*bins):
2314
+ """
2315
+ Generate a normalized (integral = 1) rectangular window in N
2316
+ dimensions. The bins parameters set the width of the window in bin
2317
+ counts in each dimension, each of which must be positive and will
2318
+ be rounded up to the nearest odd integer.
2319
+
2320
+ Example:
2321
+
2322
+ >>> tophat_window(4)
2323
+ array([ 0.2, 0.2, 0.2, 0.2, 0.2])
2324
+ >>> tophat_window(4, 4)
2325
+ array([[ 0.04, 0.04, 0.04, 0.04, 0.04],
2326
+ [ 0.04, 0.04, 0.04, 0.04, 0.04],
2327
+ [ 0.04, 0.04, 0.04, 0.04, 0.04],
2328
+ [ 0.04, 0.04, 0.04, 0.04, 0.04],
2329
+ [ 0.04, 0.04, 0.04, 0.04, 0.04]])
2330
+ """
2331
+ if not bins:
2332
+ raise ValueError("function requires at least 1 width")
2333
+ if min(bins) <= 0:
2334
+ raise ValueError("widths must be positive, got %s" % str(bins))
2335
+ windows = []
2336
+ for b in bins:
2337
+ w = lal.CreateRectangularREAL8Window(int(math.floor(b / 2.0)) * 2 + 1)
2338
+ windows.append(w.data.data / w.sum)
2339
+ if len(windows) == 1:
2340
+ # 1D short-cut
2341
+ return windows[0]
2342
+ try:
2343
+ # only works upto 26 dimensions, but that's 2 trillion bins
2344
+ # if there are just 3 bins along each side, so it's
2345
+ # unlikely to be a practical limitation; for a while at
2346
+ # least
2347
+ assert len(windows) <= 26
2348
+ return numpy.einsum(",".join("abcdefghijklmnopqrstuvwxyz"[:len(windows)]), *windows)
2349
+ except AttributeError:
2350
+ # numpy < 1.6
2351
+ window = reduce(numpy.outer, windows)
2352
+ window.shape = tuple(len(w) for w in windows)
2353
+ return window
2354
+
2355
+
2356
+ #
2357
+ # =============================================================================
2358
+ #
2359
+ # Filtering
2360
+ #
2361
+ # =============================================================================
2362
+ #
2363
+
2364
+
2365
+ def filter_array(a, window, cyclic = False, use_fft = True):
2366
+ """
2367
+ Filter an array using the window function. The transformation is
2368
+ done in place. The data are assumed to be 0 outside of their
2369
+ domain of definition. The window function must have an odd number
2370
+ of samples in each dimension; this is done so that it is always
2371
+ clear which sample is at the window's centre, which helps prevent
2372
+ phase errors. If the window function's size exceeds that of the
2373
+ data in one or more dimensions, the largest allowed central portion
2374
+ of the window function in the affected dimensions will be used.
2375
+ This is done silently; to determine if window function truncation
2376
+ will occur, check for yourself that your window function is smaller
2377
+ than your data in all dimensions.
2378
+
2379
+ If use_fft is True, the window is convolved with the array using
2380
+ FFT convolution. This is done by processing the array in bands of
2381
+ relatively small dynamic range each to work around numerical
2382
+ dynamic range limitation in the FFTs, but the window function is
2383
+ not treated similarly. As a result the window is effectively
2384
+ limited to a few orders of magnitude of dynamic range. If use_fft
2385
+ is False there are no dynamic range issues but the convolution can
2386
+ be quite slow.
2387
+ """
2388
+ assert not cyclic # no longer supported, maybe in future
2389
+ # check that the window and the data have the same number of
2390
+ # dimensions
2391
+ dims = len(a.shape)
2392
+ if dims != len(window.shape):
2393
+ raise ValueError("array and window dimensions mismatch")
2394
+ # check that all of the window's dimensions have an odd size
2395
+ if 0 in map((1).__and__, window.shape):
2396
+ raise ValueError("window size is not an odd integer in at least 1 dimension")
2397
+ # determine how much of the window function can be used
2398
+ window_slices = []
2399
+ for d in range(dims):
2400
+ if window.shape[d] > a.shape[d]:
2401
+ # largest odd integer <= size of a
2402
+ n = ((a.shape[d] + 1) // 2) * 2 - 1
2403
+ first = (window.shape[d] - n) // 2
2404
+ window_slices.append(slice(first, first + n))
2405
+ else:
2406
+ window_slices.append(slice(0, window.shape[d]))
2407
+ window = window[tuple(window_slices)]
2408
+
2409
+ if use_fft:
2410
+ # this loop works around dynamic range limits in the FFT
2411
+ # convolution code. we move data 4 orders of magnitude at
2412
+ # a time from the original array into a work space,
2413
+ # convolve the work space with the filter, zero the
2414
+ # workspace in any elements that are more than 14 orders of
2415
+ # magnitude below the maximum value in the result, and add
2416
+ # the result to the total.
2417
+ result = numpy.zeros_like(a)
2418
+ while a.any():
2419
+ # copy contents of input array to work space
2420
+ workspace = numpy.copy(a)
2421
+
2422
+ # mask = indexes of elements of work space not more
2423
+ # than 4 orders of magnitude larger than the
2424
+ # smallest non-zero element. these are the
2425
+ # elements to be processed in this iteration
2426
+ abs_workspace = abs(workspace)
2427
+ mask = abs_workspace <= abs_workspace[abs_workspace > 0].min() * 1e4
2428
+ del abs_workspace
2429
+
2430
+ # zero the masked elements in the input array, zero
2431
+ # everything except the masked elements in the work
2432
+ # space
2433
+ a[mask] = 0.
2434
+ workspace[~mask] = 0.
2435
+ del mask
2436
+
2437
+ # convolve the work space with the kernel
2438
+ workspace = signaltools.fftconvolve(workspace, window, mode = "same")
2439
+
2440
+ # determine the largest value in the work space,
2441
+ # and set to zero anything more than 14 orders of
2442
+ # magnitude smaller
2443
+ abs_workspace = abs(workspace)
2444
+ workspace[abs_workspace < abs_workspace.max() * 1e-14] = 0.
2445
+ del abs_workspace
2446
+
2447
+ # sum what remains into the result
2448
+ result += workspace
2449
+ del workspace
2450
+ else:
2451
+ result = signaltools.convolve(a, window, mode = "same")
2452
+ # overwrite the input with the result
2453
+ numpy.copyto(a, result, casting = "no")
2454
+
2455
+ return a