diff --git a/CMakeLists.txt b/CMakeLists.txt index d1382e4..456378b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,8 @@ -cmake_minimum_required(VERSION 2.6) +cmake_minimum_required(VERSION 2.9) project(bayestar) +set_property(GLOBAL PROPERTY FIND_LIBRARY_USE_LIB64_PATHS TRUE) + # # Use pkg-config to find some libraries # @@ -26,58 +28,68 @@ IF(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/.git) ELSE(GIT_FOUND) SET(GIT_BUILD_VERSION 0) ENDIF(GIT_FOUND) +ELSE(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/.git) + SET(GIT_BUILD_VERSION "$ENV{BAYESTARCOMMIT}") ENDIF(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/.git) # # Configure a header file to pass some of the CMake # settings to the source code # -#set(DATADIR "${CMAKE_INSTALL_PREFIX}/data/") set(DATADIR "${CMAKE_SOURCE_DIR}/data/") configure_file( "${PROJECT_SOURCE_DIR}/src/bayestar_config.h.in" - "${PROJECT_BINARY_DIR}/src/bayestar_config.h" + "${PROJECT_BINARY_DIR}/src/bayestar_config.h" ESCAPE_QUOTES ) include_directories("${PROJECT_BINARY_DIR}/src") -# -# Optimizations -# -IF(NOT CMAKE_COMPILER_IS_GNUCXX) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3 -ipo -axHOST -no-prec-div ") -ELSE(NOT CMAKE_COMPILER_IS_GNUCXX) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3 ") #-march=native -ENDIF(NOT CMAKE_COMPILER_IS_GNUCXX) - # # Profiling # IF(CMAKE_COMPILER_IS_GNUCXX) IF(PROFILING_GEN) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-generate -pg ") - #set(CMAKE_LD_FLAGS "${CMAKE_LD_FLAGS} -fprofile-generate=profiling/ -pg ") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-generate=prof -lgcov ") MESSAGE( STATUS "Setting flags to generate profiling information." ) ENDIF(PROFILING_GEN) IF(PROFILING_USE) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-use ") - #set(CMAKE_LD_FLAGS "${CMAKE_LD_FLAGS} -fprofile-use=profiling/ ") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-use=prof ") MESSAGE( STATUS "Setting flags to use profiling information." ) ENDIF(PROFILING_USE) ENDIF(CMAKE_COMPILER_IS_GNUCXX) -### OpenCV -pkg_check_modules(OPENCV opencv) -include_directories(${OPENCV_INCLUDE_DIRS}) -link_directories(${OPENCV_LIBRARY_DIRS}) -MESSAGE( STATUS "OPENCV_LIBRARY_DIRS: ${OPENCV_LIBRARY_DIRS}" ) -MESSAGE( STATUS "OPENCV_INCLUDE_DIRS: ${OPENCV_INCLUDE_DIRS}" ) -MESSAGE( STATUS "OPENCV_LIBRARIES: ${OPENCV_LIBRARIES}" ) +# +# Optimizations +# +IF(NOT CMAKE_COMPILER_IS_GNUCXX) + set(CMAKE_CXX_COMPILER icx) + # set(CMAKE_CXX_COMPILER icc) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3 -ipo -xHOST -fp-model precise ") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 ") +ELSE(NOT CMAKE_COMPILER_IS_GNUCXX) + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS} -O3 -march=native ") + set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS} -O1 -g ") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --std=c++14 ") +ENDIF(NOT CMAKE_COMPILER_IS_GNUCXX) -### GSL -find_package(GSL REQUIRED) -include_directories(${GSL_INCLUDE_DIR}) -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DHAVE_INLINE=1 -DGSL_RANGE_CHECK=0") +MESSAGE( STATUS "CMAKE_COMPILER_IS_GNUCXX: ${CMAKE_COMPILER_IS_GNUCXX}" ) +MESSAGE( STATUS "CMAKE_CXX_FLAGS_RELEASE: ${CMAKE_CXX_FLAGS_RELEASE}" ) + +### HDF5 +find_package(HDF5 COMPONENTS C CXX HL REQUIRED) +include_directories(${HDF5_INCLUDE_DIRS}) +MESSAGE( STATUS "HDF5_INCLUDE_DIRS: ${HDF5_INCLUDE_DIRS}" ) +MESSAGE( STATUS "HDF5_LIBRARY_DIRS: ${HDF5_LIBRARY_DIRS}" ) +MESSAGE( STATUS "HDF5_LIBRARIES: ${HDF5_LIBRARIES}" ) +MESSAGE( STATUS "HDF5_CXX_LIBRARIES: ${HDF5_CXX_LIBRARIES}" ) + +### OpenCV +find_package(OpenCV 4 REQUIRED) +include_directories(${OpenCV_INCLUDE_DIRS}) +link_directories(${OpenCV_LIBRARY_DIRS}) +MESSAGE( STATUS "OPENCV_LIBRARY_DIRS: ${OpenCV_LIBRARY_DIRS}" ) +MESSAGE( STATUS "OPENCV_INCLUDE_DIRS: ${OpenCV_INCLUDE_DIRS}" ) +MESSAGE( STATUS "OPENCV_LIBRARIES: ${OpenCV_LIBRARIES}" ) ### Boost find_package(Boost REQUIRED COMPONENTS program_options) @@ -85,15 +97,27 @@ include_directories(${Boost_INCLUDE_DIRS}) MESSAGE( STATUS "Boost_INCLUDE_DIRS: ${Boost_INCLUDE_DIRS}" ) MESSAGE( STATUS "Boost_LIBRARIES: ${Boost_LIBRARIES}" ) - ### OpenMP support -#find_package(OpenMP REQUIRED) IF(NOT CMAKE_COMPILER_IS_GNUCXX) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -openmp") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -qopenmp") ELSE(NOT CMAKE_COMPILER_IS_GNUCXX) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fopenmp") ENDIF(NOT CMAKE_COMPILER_IS_GNUCXX) -#set(CMAKE_C_FLAGS ${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}) + +### EIGEN3 +pkg_check_modules(EIGEN3 eigen3) +#find_package(Eigen3 REQUIRED NO_MODULES) +include_directories(${EIGEN3_INCLUDE_DIRS}) +MESSAGE( STATUS "EIGEN3_INCLUDE_DIRS: ${EIGEN3_INCLUDE_DIRS}" ) +MESSAGE( STATUS "EIGEN3_LIBRARIES: ${EIGEN3_LIBRARIES}" ) + +### GSL +pkg_check_modules(GSL gsl) +#find_package(GSL REQUIRED) +MESSAGE( STATUS "GSL_INCLUDE_DIRS: ${GSL_INCLUDE_DIR}" ) +MESSAGE( STATUS "GSL_LIBRARY_DIRS: ${GSL_LIBRARY_DIRS}" ) +include_directories(${GSL_INCLUDE_DIR}) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DHAVE_INLINE=1 -DGSL_RANGE_CHECK=0") ### Fixed-size types set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D__STDC_LIMIT_MACROS") @@ -103,15 +127,23 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D__STDC_LIMIT_MACROS") # add_executable(bayestar src/main.cpp src/model.cpp src/sampler.cpp src/interpolation.cpp src/stats.cpp src/chain.cpp - src/data.cpp src/binner.cpp src/los_sampler.cpp src/h5utils.cpp) + src/data.cpp src/binner.cpp src/los_sampler.cpp + src/h5utils.cpp src/star_exact.cpp + src/program_opts.cpp src/gaussian_process.cpp + src/healpix_tree.cpp src/neighbor_pixels.cpp + src/bridging_sampler.cpp) # # Link libraries # target_link_libraries(bayestar rt) -target_link_libraries(bayestar hdf5 hdf5_cpp) +target_link_libraries(bayestar ${HDF5_LIBRARIES} stdc++) target_link_libraries(bayestar ${GSL_LIBRARIES}) target_link_libraries(bayestar ${Boost_LIBRARIES}) -target_link_libraries(bayestar opencv_core opencv_imgproc) -#target_link_libraries(bayestar ${OPENCV_LIBRARIES}) +target_link_libraries(bayestar ${OpenCV_LIBRARIES}) #target_link_libraries(bayestar ${OpenMP_LIBRARIES}) +target_link_libraries(bayestar ${EIGEN3_LIBRARIES}) +IF(ADDITIONAL_LINK_DIRS) + target_link_libraries(bayestar -L${ADDITIONAL_LINK_DIRS}) + MESSAGE( STATUS "Additional link directories: ${ADDITIONAL_LINK_DIRS}" ) +ENDIF(ADDITIONAL_LINK_DIRS) diff --git a/README.txt b/README.txt index e69de29..f5ce81d 100644 --- a/README.txt +++ b/README.txt @@ -0,0 +1 @@ +Andrew Saydjari updated this (forked) version of Bayestar for the DECaPS dust map run from Greg M. Green's original repo. The main changes were just to make it compile with modern compilers. The src/, cmake/, and data/ directories were updated accordingly. No guarantees are made about the scripts/ and input/ directories. A more recent config-example.txt file is also included. Any questions can be directed to andrew-saydjari or gregreen. \ No newline at end of file diff --git a/cmake/modules/FindBoost.cmake b/cmake/modules/FindBoost.cmake new file mode 100644 index 0000000..72a9a4c --- /dev/null +++ b/cmake/modules/FindBoost.cmake @@ -0,0 +1,2590 @@ +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying +# file Copyright.txt or https://cmake.org/licensing for details. + +#[=======================================================================[.rst: +FindBoost +--------- + +Find Boost include dirs and libraries + +Use this module by invoking :command:`find_package` with the form: + +.. code-block:: cmake + + find_package(Boost + [version] [EXACT] # Minimum or EXACT version e.g. 1.67.0 + [REQUIRED] # Fail with error if Boost is not found + [COMPONENTS ...] # Boost libraries by their canonical name + # e.g. "date_time" for "libboost_date_time" + [OPTIONAL_COMPONENTS ...] + # Optional Boost libraries by their canonical name) + ) # e.g. "date_time" for "libboost_date_time" + +This module finds headers and requested component libraries OR a CMake +package configuration file provided by a "Boost CMake" build. For the +latter case skip to the :ref:`Boost CMake` section below. + +.. versionadded:: 3.7 + ``bzip2`` and ``zlib`` components (Windows only). + +.. versionadded:: 3.11 + The ``OPTIONAL_COMPONENTS`` option. + +.. versionadded:: 3.13 + ``stacktrace_*`` components. + +.. versionadded:: 3.19 + ``bzip2`` and ``zlib`` components on all platforms. + +Result Variables +^^^^^^^^^^^^^^^^ + +This module defines the following variables: + +``Boost_FOUND`` + True if headers and requested libraries were found. + +``Boost_INCLUDE_DIRS`` + Boost include directories. + +``Boost_LIBRARY_DIRS`` + Link directories for Boost libraries. + +``Boost_LIBRARIES`` + Boost component libraries to be linked. + +``Boost__FOUND`` + True if component ```` was found (```` name is upper-case). + +``Boost__LIBRARY`` + Libraries to link for component ```` (may include + :command:`target_link_libraries` debug/optimized keywords). + +``Boost_VERSION_MACRO`` + ``BOOST_VERSION`` value from ``boost/version.hpp``. + +``Boost_VERSION_STRING`` + Boost version number in ``X.Y.Z`` format. + +``Boost_VERSION`` + Boost version number in ``X.Y.Z`` format (same as ``Boost_VERSION_STRING``). + + .. versionchanged:: 3.15 + In previous CMake versions, this variable used the raw version string + from the Boost header (same as ``Boost_VERSION_MACRO``). + See policy :policy:`CMP0093`. + +``Boost_LIB_VERSION`` + Version string appended to library filenames. + +``Boost_VERSION_MAJOR``, ``Boost_MAJOR_VERSION`` + Boost major version number (``X`` in ``X.Y.Z``). + +``Boost_VERSION_MINOR``, ``Boost_MINOR_VERSION`` + Boost minor version number (``Y`` in ``X.Y.Z``). + +``Boost_VERSION_PATCH``, ``Boost_SUBMINOR_VERSION`` + Boost subminor version number (``Z`` in ``X.Y.Z``). + +``Boost_VERSION_COUNT`` + Amount of version components (3). + +``Boost_LIB_DIAGNOSTIC_DEFINITIONS`` (Windows-specific) + Pass to :command:`add_definitions` to have diagnostic + information about Boost's automatic linking + displayed during compilation + +.. versionadded:: 3.15 + The ``Boost_VERSION_`` variables. + +Cache variables +^^^^^^^^^^^^^^^ + +Search results are saved persistently in CMake cache entries: + +``Boost_INCLUDE_DIR`` + Directory containing Boost headers. + +``Boost_LIBRARY_DIR_RELEASE`` + Directory containing release Boost libraries. + +``Boost_LIBRARY_DIR_DEBUG`` + Directory containing debug Boost libraries. + +``Boost__LIBRARY_DEBUG`` + Component ```` library debug variant. + +``Boost__LIBRARY_RELEASE`` + Component ```` library release variant. + +.. versionadded:: 3.3 + Per-configuration variables ``Boost_LIBRARY_DIR_RELEASE`` and + ``Boost_LIBRARY_DIR_DEBUG``. + +Hints +^^^^^ + +This module reads hints about search locations from variables: + +``BOOST_ROOT``, ``BOOSTROOT`` + Preferred installation prefix. + +``BOOST_INCLUDEDIR`` + Preferred include directory e.g. ``/include``. + +``BOOST_LIBRARYDIR`` + Preferred library directory e.g. ``/lib``. + +``Boost_NO_SYSTEM_PATHS`` + Set to ``ON`` to disable searching in locations not + specified by these hint variables. Default is ``OFF``. + +``Boost_ADDITIONAL_VERSIONS`` + List of Boost versions not known to this module. + (Boost install locations may contain the version). + +Users may set these hints or results as ``CACHE`` entries. Projects +should not read these entries directly but instead use the above +result variables. Note that some hint names start in upper-case +``BOOST``. One may specify these as environment variables if they are +not specified as CMake variables or cache entries. + +This module first searches for the Boost header files using the above +hint variables (excluding ``BOOST_LIBRARYDIR``) and saves the result in +``Boost_INCLUDE_DIR``. Then it searches for requested component libraries +using the above hints (excluding ``BOOST_INCLUDEDIR`` and +``Boost_ADDITIONAL_VERSIONS``), "lib" directories near ``Boost_INCLUDE_DIR``, +and the library name configuration settings below. It saves the +library directories in ``Boost_LIBRARY_DIR_DEBUG`` and +``Boost_LIBRARY_DIR_RELEASE`` and individual library +locations in ``Boost__LIBRARY_DEBUG`` and ``Boost__LIBRARY_RELEASE``. +When one changes settings used by previous searches in the same build +tree (excluding environment variables) this module discards previous +search results affected by the changes and searches again. + +Imported Targets +^^^^^^^^^^^^^^^^ + +.. versionadded:: 3.5 + +This module defines the following :prop_tgt:`IMPORTED` targets: + +``Boost::boost`` + Target for header-only dependencies. (Boost include directory). + +``Boost::headers`` + .. versionadded:: 3.15 + Alias for ``Boost::boost``. + +``Boost::`` + Target for specific component dependency (shared or static library); + ```` name is lower-case. + +``Boost::diagnostic_definitions`` + Interface target to enable diagnostic information about Boost's automatic + linking during compilation (adds ``-DBOOST_LIB_DIAGNOSTIC``). + +``Boost::disable_autolinking`` + Interface target to disable automatic linking with MSVC + (adds ``-DBOOST_ALL_NO_LIB``). + +``Boost::dynamic_linking`` + Interface target to enable dynamic linking with MSVC + (adds ``-DBOOST_ALL_DYN_LINK``). + +Implicit dependencies such as ``Boost::filesystem`` requiring +``Boost::system`` will be automatically detected and satisfied, even +if system is not specified when using :command:`find_package` and if +``Boost::system`` is not added to :command:`target_link_libraries`. If using +``Boost::thread``, then ``Threads::Threads`` will also be added automatically. + +It is important to note that the imported targets behave differently +than variables created by this module: multiple calls to +:command:`find_package(Boost)` in the same directory or sub-directories with +different options (e.g. static or shared) will not override the +values of the targets created by the first call. + +Other Variables +^^^^^^^^^^^^^^^ + +Boost libraries come in many variants encoded in their file name. +Users or projects may tell this module which variant to find by +setting variables: + +``Boost_USE_DEBUG_LIBS`` + .. versionadded:: 3.10 + + Set to ``ON`` or ``OFF`` to specify whether to search and use the debug + libraries. Default is ``ON``. + +``Boost_USE_RELEASE_LIBS`` + .. versionadded:: 3.10 + + Set to ``ON`` or ``OFF`` to specify whether to search and use the release + libraries. Default is ``ON``. + +``Boost_USE_MULTITHREADED`` + Set to OFF to use the non-multithreaded libraries ("mt" tag). Default is + ``ON``. + +``Boost_USE_STATIC_LIBS`` + Set to ON to force the use of the static libraries. Default is ``OFF``. + +``Boost_USE_STATIC_RUNTIME`` + Set to ``ON`` or ``OFF`` to specify whether to use libraries linked + statically to the C++ runtime ("s" tag). Default is platform dependent. + +``Boost_USE_DEBUG_RUNTIME`` + Set to ``ON`` or ``OFF`` to specify whether to use libraries linked to the + MS debug C++ runtime ("g" tag). Default is ``ON``. + +``Boost_USE_DEBUG_PYTHON`` + Set to ``ON`` to use libraries compiled with a debug Python build ("y" + tag). Default is ``OFF``. + +``Boost_USE_STLPORT`` + Set to ``ON`` to use libraries compiled with STLPort ("p" tag). Default is + ``OFF``. + +``Boost_USE_STLPORT_DEPRECATED_NATIVE_IOSTREAMS`` + Set to ON to use libraries compiled with STLPort deprecated "native + iostreams" ("n" tag). Default is ``OFF``. + +``Boost_COMPILER`` + Set to the compiler-specific library suffix (e.g. ``-gcc43``). Default is + auto-computed for the C++ compiler in use. + + .. versionchanged:: 3.9 + A list may be used if multiple compatible suffixes should be tested for, + in decreasing order of preference. + +``Boost_LIB_PREFIX`` + .. versionadded:: 3.18 + + Set to the platform-specific library name prefix (e.g. ``lib``) used by + Boost static libs. This is needed only on platforms where CMake does not + know the prefix by default. + +``Boost_ARCHITECTURE`` + .. versionadded:: 3.13 + + Set to the architecture-specific library suffix (e.g. ``-x64``). + Default is auto-computed for the C++ compiler in use. + +``Boost_THREADAPI`` + Suffix for ``thread`` component library name, such as ``pthread`` or + ``win32``. Names with and without this suffix will both be tried. + +``Boost_NAMESPACE`` + Alternate namespace used to build boost with e.g. if set to ``myboost``, + will search for ``myboost_thread`` instead of ``boost_thread``. + +Other variables one may set to control this module are: + +``Boost_DEBUG`` + Set to ``ON`` to enable debug output from ``FindBoost``. + Please enable this before filing any bug report. + +``Boost_REALPATH`` + Set to ``ON`` to resolve symlinks for discovered libraries to assist with + packaging. For example, the "system" component library may be resolved to + ``/usr/lib/libboost_system.so.1.67.0`` instead of + ``/usr/lib/libboost_system.so``. This does not affect linking and should + not be enabled unless the user needs this information. + +``Boost_LIBRARY_DIR`` + Default value for ``Boost_LIBRARY_DIR_RELEASE`` and + ``Boost_LIBRARY_DIR_DEBUG``. + +``Boost_NO_WARN_NEW_VERSIONS`` + .. versionadded:: 3.20 + + Set to ``ON`` to suppress the warning about unknown dependencies for new + Boost versions. + +On Visual Studio and Borland compilers Boost headers request automatic +linking to corresponding libraries. This requires matching libraries +to be linked explicitly or available in the link library search path. +In this case setting ``Boost_USE_STATIC_LIBS`` to ``OFF`` may not achieve +dynamic linking. Boost automatic linking typically requests static +libraries with a few exceptions (such as ``Boost.Python``). Use: + +.. code-block:: cmake + + add_definitions(${Boost_LIB_DIAGNOSTIC_DEFINITIONS}) + +to ask Boost to report information about automatic linking requests. + +Examples +^^^^^^^^ + +Find Boost headers only: + +.. code-block:: cmake + + find_package(Boost 1.36.0) + if(Boost_FOUND) + include_directories(${Boost_INCLUDE_DIRS}) + add_executable(foo foo.cc) + endif() + +Find Boost libraries and use imported targets: + +.. code-block:: cmake + + find_package(Boost 1.56 REQUIRED COMPONENTS + date_time filesystem iostreams) + add_executable(foo foo.cc) + target_link_libraries(foo Boost::date_time Boost::filesystem + Boost::iostreams) + +Find Boost Python 3.6 libraries and use imported targets: + +.. code-block:: cmake + + find_package(Boost 1.67 REQUIRED COMPONENTS + python36 numpy36) + add_executable(foo foo.cc) + target_link_libraries(foo Boost::python36 Boost::numpy36) + +Find Boost headers and some *static* (release only) libraries: + +.. code-block:: cmake + + set(Boost_USE_STATIC_LIBS ON) # only find static libs + set(Boost_USE_DEBUG_LIBS OFF) # ignore debug libs and + set(Boost_USE_RELEASE_LIBS ON) # only find release libs + set(Boost_USE_MULTITHREADED ON) + set(Boost_USE_STATIC_RUNTIME OFF) + find_package(Boost 1.66.0 COMPONENTS date_time filesystem system ...) + if(Boost_FOUND) + include_directories(${Boost_INCLUDE_DIRS}) + add_executable(foo foo.cc) + target_link_libraries(foo ${Boost_LIBRARIES}) + endif() + +.. _`Boost CMake`: + +Boost CMake +^^^^^^^^^^^ + +If Boost was built using the boost-cmake project or from Boost 1.70.0 on +it provides a package configuration file for use with find_package's config mode. +This module looks for the package configuration file called +``BoostConfig.cmake`` or ``boost-config.cmake`` and stores the result in +``CACHE`` entry ``Boost_DIR``. If found, the package configuration file is loaded +and this module returns with no further action. See documentation of +the Boost CMake package configuration for details on what it provides. + +Set ``Boost_NO_BOOST_CMAKE`` to ``ON``, to disable the search for boost-cmake. +#]=======================================================================] + +# The FPHSA helper provides standard way of reporting final search results to +# the user including the version and component checks. +include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake) + +# Save project's policies +cmake_policy(PUSH) +cmake_policy(SET CMP0057 NEW) # if IN_LIST +cmake_policy(SET CMP0102 NEW) # if mark_as_advanced(non_cache_var) + +function(_boost_get_existing_target component target_var) + set(names "${component}") + if(component MATCHES "^([a-z_]*)(python|numpy)([1-9])\\.?([0-9]+)?$") + # handle pythonXY and numpyXY versioned components and also python X.Y, mpi_python etc. + list(APPEND names + "${CMAKE_MATCH_1}${CMAKE_MATCH_2}" # python + "${CMAKE_MATCH_1}${CMAKE_MATCH_2}${CMAKE_MATCH_3}" # pythonX + "${CMAKE_MATCH_1}${CMAKE_MATCH_2}${CMAKE_MATCH_3}${CMAKE_MATCH_4}" #pythonXY + ) + endif() + # https://github.com/boost-cmake/boost-cmake uses boost::file_system etc. + # So handle similar constructions of target names + string(TOLOWER "${component}" lower_component) + list(APPEND names "${lower_component}") + foreach(prefix Boost boost) + foreach(name IN LISTS names) + if(TARGET "${prefix}::${name}") + # The target may be an INTERFACE library that wraps around a single other + # target for compatibility. Unwrap this layer so we can extract real info. + if("${name}" MATCHES "^(python|numpy|mpi_python)([1-9])([0-9]+)$") + set(name_nv "${CMAKE_MATCH_1}") + if(TARGET "${prefix}::${name_nv}") + get_property(type TARGET "${prefix}::${name}" PROPERTY TYPE) + if(type STREQUAL "INTERFACE_LIBRARY") + get_property(lib TARGET "${prefix}::${name}" PROPERTY INTERFACE_LINK_LIBRARIES) + if("${lib}" STREQUAL "${prefix}::${name_nv}") + set(${target_var} "${prefix}::${name_nv}" PARENT_SCOPE) + return() + endif() + endif() + endif() + endif() + set(${target_var} "${prefix}::${name}" PARENT_SCOPE) + return() + endif() + endforeach() + endforeach() + set(${target_var} "" PARENT_SCOPE) +endfunction() + +function(_boost_get_canonical_target_name component target_var) + string(TOLOWER "${component}" component) + if(component MATCHES "^([a-z_]*)(python|numpy)([1-9])\\.?([0-9]+)?$") + # handle pythonXY and numpyXY versioned components and also python X.Y, mpi_python etc. + set(${target_var} "Boost::${CMAKE_MATCH_1}${CMAKE_MATCH_2}" PARENT_SCOPE) + else() + set(${target_var} "Boost::${component}" PARENT_SCOPE) + endif() +endfunction() + +macro(_boost_set_in_parent_scope name value) + # Set a variable in parent scope and make it visible in current scope + set(${name} "${value}" PARENT_SCOPE) + set(${name} "${value}") +endmacro() + +macro(_boost_set_if_unset name value) + if(NOT ${name}) + _boost_set_in_parent_scope(${name} "${value}") + endif() +endmacro() + +macro(_boost_set_cache_if_unset name value) + if(NOT ${name}) + set(${name} "${value}" CACHE STRING "" FORCE) + endif() +endmacro() + +macro(_boost_append_include_dir target) + get_target_property(inc "${target}" INTERFACE_INCLUDE_DIRECTORIES) + if(inc) + list(APPEND include_dirs "${inc}") + endif() +endmacro() + +function(_boost_set_legacy_variables_from_config) + # Set legacy variables for compatibility if not set + set(include_dirs "") + set(library_dirs "") + set(libraries "") + # Header targets Boost::headers or Boost::boost + foreach(comp headers boost) + _boost_get_existing_target(${comp} target) + if(target) + _boost_append_include_dir("${target}") + endif() + endforeach() + # Library targets + foreach(comp IN LISTS Boost_FIND_COMPONENTS) + string(TOUPPER ${comp} uppercomp) + # Overwrite if set + _boost_set_in_parent_scope(Boost_${uppercomp}_FOUND "${Boost_${comp}_FOUND}") + if(Boost_${comp}_FOUND) + _boost_get_existing_target(${comp} target) + if(NOT target) + if(Boost_DEBUG OR Boost_VERBOSE) + message(WARNING "Could not find imported target for required component '${comp}'. Legacy variables for this component might be missing. Refer to the documentation of your Boost installation for help on variables to use.") + endif() + continue() + endif() + _boost_append_include_dir("${target}") + _boost_set_if_unset(Boost_${uppercomp}_LIBRARY "${target}") + _boost_set_if_unset(Boost_${uppercomp}_LIBRARIES "${target}") # Very old legacy variable + list(APPEND libraries "${target}") + get_property(type TARGET "${target}" PROPERTY TYPE) + if(NOT type STREQUAL "INTERFACE_LIBRARY") + foreach(cfg RELEASE DEBUG) + get_target_property(lib ${target} IMPORTED_LOCATION_${cfg}) + if(lib) + get_filename_component(lib_dir "${lib}" DIRECTORY) + list(APPEND library_dirs ${lib_dir}) + _boost_set_cache_if_unset(Boost_${uppercomp}_LIBRARY_${cfg} "${lib}") + endif() + endforeach() + elseif(Boost_DEBUG OR Boost_VERBOSE) + # For projects using only the Boost::* targets this warning can be safely ignored. + message(WARNING "Imported target '${target}' for required component '${comp}' has no artifact. Legacy variables for this component might be missing. Refer to the documentation of your Boost installation for help on variables to use.") + endif() + _boost_get_canonical_target_name("${comp}" canonical_target) + if(NOT TARGET "${canonical_target}") + add_library("${canonical_target}" INTERFACE IMPORTED) + target_link_libraries("${canonical_target}" INTERFACE "${target}") + endif() + endif() + endforeach() + list(REMOVE_DUPLICATES include_dirs) + list(REMOVE_DUPLICATES library_dirs) + _boost_set_if_unset(Boost_INCLUDE_DIRS "${include_dirs}") + _boost_set_if_unset(Boost_LIBRARY_DIRS "${library_dirs}") + _boost_set_if_unset(Boost_LIBRARIES "${libraries}") + _boost_set_if_unset(Boost_VERSION_STRING "${Boost_VERSION_MAJOR}.${Boost_VERSION_MINOR}.${Boost_VERSION_PATCH}") + find_path(Boost_INCLUDE_DIR + NAMES boost/version.hpp boost/config.hpp + HINTS ${Boost_INCLUDE_DIRS} + NO_DEFAULT_PATH + ) + if(NOT Boost_VERSION_MACRO OR NOT Boost_LIB_VERSION) + set(version_file ${Boost_INCLUDE_DIR}/boost/version.hpp) + if(EXISTS "${version_file}") + file(STRINGS "${version_file}" contents REGEX "#define BOOST_(LIB_)?VERSION ") + if(contents MATCHES "#define BOOST_VERSION ([0-9]+)") + _boost_set_if_unset(Boost_VERSION_MACRO "${CMAKE_MATCH_1}") + endif() + if(contents MATCHES "#define BOOST_LIB_VERSION \"([0-9_]+)\"") + _boost_set_if_unset(Boost_LIB_VERSION "${CMAKE_MATCH_1}") + endif() + endif() + endif() + _boost_set_if_unset(Boost_MAJOR_VERSION ${Boost_VERSION_MAJOR}) + _boost_set_if_unset(Boost_MINOR_VERSION ${Boost_VERSION_MINOR}) + _boost_set_if_unset(Boost_SUBMINOR_VERSION ${Boost_VERSION_PATCH}) + if(WIN32) + _boost_set_if_unset(Boost_LIB_DIAGNOSTIC_DEFINITIONS "-DBOOST_LIB_DIAGNOSTIC") + endif() + if(NOT TARGET Boost::headers) + add_library(Boost::headers INTERFACE IMPORTED) + target_include_directories(Boost::headers INTERFACE ${Boost_INCLUDE_DIRS}) + endif() + # Legacy targets w/o functionality as all handled by defined targets + foreach(lib diagnostic_definitions disable_autolinking dynamic_linking) + if(NOT TARGET Boost::${lib}) + add_library(Boost::${lib} INTERFACE IMPORTED) + endif() + endforeach() + if(NOT TARGET Boost::boost) + add_library(Boost::boost INTERFACE IMPORTED) + target_link_libraries(Boost::boost INTERFACE Boost::headers) + endif() +endfunction() + +#------------------------------------------------------------------------------- +# Before we go searching, check whether a boost cmake package is available, unless +# the user specifically asked NOT to search for one. +# +# If Boost_DIR is set, this behaves as any find_package call would. If not, +# it looks at BOOST_ROOT and BOOSTROOT to find Boost. +# +if (NOT Boost_NO_BOOST_CMAKE) + # If Boost_DIR is not set, look for BOOSTROOT and BOOST_ROOT as alternatives, + # since these are more conventional for Boost. + if ("$ENV{Boost_DIR}" STREQUAL "") + if (NOT "$ENV{BOOST_ROOT}" STREQUAL "") + set(ENV{Boost_DIR} $ENV{BOOST_ROOT}) + elseif (NOT "$ENV{BOOSTROOT}" STREQUAL "") + set(ENV{Boost_DIR} $ENV{BOOSTROOT}) + endif() + endif() + + set(_boost_FIND_PACKAGE_ARGS "") + if(Boost_NO_SYSTEM_PATHS) + list(APPEND _boost_FIND_PACKAGE_ARGS NO_CMAKE_SYSTEM_PATH NO_SYSTEM_ENVIRONMENT_PATH) + endif() + + # Do the same find_package call but look specifically for the CMake version. + # Note that args are passed in the Boost_FIND_xxxxx variables, so there is no + # need to delegate them to this find_package call. + if(BOOST_ROOT AND NOT Boost_ROOT) + # Honor BOOST_ROOT by setting Boost_ROOT with CMP0074 NEW behavior. + cmake_policy(PUSH) + cmake_policy(SET CMP0074 NEW) + set(Boost_ROOT "${BOOST_ROOT}") + set(_Boost_ROOT_FOR_CONFIG 1) + endif() + find_package(Boost QUIET NO_MODULE ${_boost_FIND_PACKAGE_ARGS}) + if(_Boost_ROOT_FOR_CONFIG) + unset(_Boost_ROOT_FOR_CONFIG) + unset(Boost_ROOT) + cmake_policy(POP) + endif() + if (DEFINED Boost_DIR) + mark_as_advanced(Boost_DIR) + endif () + + # If we found a boost cmake package, then we're done. Print out what we found. + # Otherwise let the rest of the module try to find it. + if(Boost_FOUND) + # Convert component found variables to standard variables if required + # Necessary for legacy boost-cmake and 1.70 builtin BoostConfig + if(Boost_FIND_COMPONENTS) + # Ignore the meta-component "ALL", introduced by Boost 1.73 + list(REMOVE_ITEM Boost_FIND_COMPONENTS "ALL") + + foreach(_comp IN LISTS Boost_FIND_COMPONENTS) + if(DEFINED Boost_${_comp}_FOUND) + continue() + endif() + string(TOUPPER ${_comp} _uppercomp) + if(DEFINED Boost${_comp}_FOUND) # legacy boost-cmake project + set(Boost_${_comp}_FOUND ${Boost${_comp}_FOUND}) + elseif(DEFINED Boost_${_uppercomp}_FOUND) # Boost 1.70 + set(Boost_${_comp}_FOUND ${Boost_${_uppercomp}_FOUND}) + endif() + endforeach() + endif() + + find_package_handle_standard_args(Boost HANDLE_COMPONENTS CONFIG_MODE) + _boost_set_legacy_variables_from_config() + + # Restore project's policies + cmake_policy(POP) + return() + endif() +endif() + + +#------------------------------------------------------------------------------- +# FindBoost functions & macros +# + +# +# Print debug text if Boost_DEBUG is set. +# Call example: +# _Boost_DEBUG_PRINT("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "debug message") +# +function(_Boost_DEBUG_PRINT file line text) + if(Boost_DEBUG) + message(STATUS "[ ${file}:${line} ] ${text}") + endif() +endfunction() + +# +# _Boost_DEBUG_PRINT_VAR(file line variable_name [ENVIRONMENT] +# [SOURCE "short explanation of origin of var value"]) +# +# ENVIRONMENT - look up environment variable instead of CMake variable +# +# Print variable name and its value if Boost_DEBUG is set. +# Call example: +# _Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" BOOST_ROOT) +# +function(_Boost_DEBUG_PRINT_VAR file line name) + if(Boost_DEBUG) + cmake_parse_arguments(_args "ENVIRONMENT" "SOURCE" "" ${ARGN}) + + unset(source) + if(_args_SOURCE) + set(source " (${_args_SOURCE})") + endif() + + if(_args_ENVIRONMENT) + if(DEFINED ENV{${name}}) + set(value "\"$ENV{${name}}\"") + else() + set(value "") + endif() + set(_name "ENV{${name}}") + else() + if(DEFINED "${name}") + set(value "\"${${name}}\"") + else() + set(value "") + endif() + set(_name "${name}") + endif() + + _Boost_DEBUG_PRINT("${file}" "${line}" "${_name} = ${value}${source}") + endif() +endfunction() + +############################################ +# +# Check the existence of the libraries. +# +############################################ +# This macro was taken directly from the FindQt4.cmake file that is included +# with the CMake distribution. This is NOT my work. All work was done by the +# original authors of the FindQt4.cmake file. Only minor modifications were +# made to remove references to Qt and make this file more generally applicable +# And ELSE/ENDIF pairs were removed for readability. +######################################################################### + +macro(_Boost_ADJUST_LIB_VARS basename) + if(Boost_INCLUDE_DIR ) + if(Boost_${basename}_LIBRARY_DEBUG AND Boost_${basename}_LIBRARY_RELEASE) + # if the generator is multi-config or if CMAKE_BUILD_TYPE is set for + # single-config generators, set optimized and debug libraries + get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) + if(_isMultiConfig OR CMAKE_BUILD_TYPE) + set(Boost_${basename}_LIBRARY optimized ${Boost_${basename}_LIBRARY_RELEASE} debug ${Boost_${basename}_LIBRARY_DEBUG}) + else() + # For single-config generators where CMAKE_BUILD_TYPE has no value, + # just use the release libraries + set(Boost_${basename}_LIBRARY ${Boost_${basename}_LIBRARY_RELEASE} ) + endif() + # FIXME: This probably should be set for both cases + set(Boost_${basename}_LIBRARIES optimized ${Boost_${basename}_LIBRARY_RELEASE} debug ${Boost_${basename}_LIBRARY_DEBUG}) + endif() + + # if only the release version was found, set the debug variable also to the release version + if(Boost_${basename}_LIBRARY_RELEASE AND NOT Boost_${basename}_LIBRARY_DEBUG) + set(Boost_${basename}_LIBRARY_DEBUG ${Boost_${basename}_LIBRARY_RELEASE}) + set(Boost_${basename}_LIBRARY ${Boost_${basename}_LIBRARY_RELEASE}) + set(Boost_${basename}_LIBRARIES ${Boost_${basename}_LIBRARY_RELEASE}) + endif() + + # if only the debug version was found, set the release variable also to the debug version + if(Boost_${basename}_LIBRARY_DEBUG AND NOT Boost_${basename}_LIBRARY_RELEASE) + set(Boost_${basename}_LIBRARY_RELEASE ${Boost_${basename}_LIBRARY_DEBUG}) + set(Boost_${basename}_LIBRARY ${Boost_${basename}_LIBRARY_DEBUG}) + set(Boost_${basename}_LIBRARIES ${Boost_${basename}_LIBRARY_DEBUG}) + endif() + + # If the debug & release library ends up being the same, omit the keywords + if("${Boost_${basename}_LIBRARY_RELEASE}" STREQUAL "${Boost_${basename}_LIBRARY_DEBUG}") + set(Boost_${basename}_LIBRARY ${Boost_${basename}_LIBRARY_RELEASE} ) + set(Boost_${basename}_LIBRARIES ${Boost_${basename}_LIBRARY_RELEASE} ) + endif() + + if(Boost_${basename}_LIBRARY AND Boost_${basename}_HEADER) + set(Boost_${basename}_FOUND ON) + if("x${basename}" STREQUAL "xTHREAD" AND NOT TARGET Threads::Threads) + string(APPEND Boost_ERROR_REASON_THREAD " (missing dependency: Threads)") + set(Boost_THREAD_FOUND OFF) + endif() + endif() + + endif() + # Make variables changeable to the advanced user + mark_as_advanced( + Boost_${basename}_LIBRARY_RELEASE + Boost_${basename}_LIBRARY_DEBUG + ) +endmacro() + +# Detect changes in used variables. +# Compares the current variable value with the last one. +# In short form: +# v != v_LAST -> CHANGED = 1 +# v is defined, v_LAST not -> CHANGED = 1 +# v is not defined, but v_LAST is -> CHANGED = 1 +# otherwise -> CHANGED = 0 +# CHANGED is returned in variable named ${changed_var} +macro(_Boost_CHANGE_DETECT changed_var) + set(${changed_var} 0) + foreach(v ${ARGN}) + if(DEFINED _Boost_COMPONENTS_SEARCHED) + if(${v}) + if(_${v}_LAST) + string(COMPARE NOTEQUAL "${${v}}" "${_${v}_LAST}" _${v}_CHANGED) + else() + set(_${v}_CHANGED 1) + endif() + elseif(_${v}_LAST) + set(_${v}_CHANGED 1) + endif() + if(_${v}_CHANGED) + set(${changed_var} 1) + endif() + else() + set(_${v}_CHANGED 0) + endif() + endforeach() +endmacro() + +# +# Find the given library (var). +# Use 'build_type' to support different lib paths for RELEASE or DEBUG builds +# +macro(_Boost_FIND_LIBRARY var build_type) + + find_library(${var} ${ARGN}) + + if(${var}) + # If this is the first library found then save Boost_LIBRARY_DIR_[RELEASE,DEBUG]. + if(NOT Boost_LIBRARY_DIR_${build_type}) + get_filename_component(_dir "${${var}}" PATH) + set(Boost_LIBRARY_DIR_${build_type} "${_dir}" CACHE PATH "Boost library directory ${build_type}" FORCE) + endif() + elseif(_Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT) + # Try component-specific hints but do not save Boost_LIBRARY_DIR_[RELEASE,DEBUG]. + find_library(${var} HINTS ${_Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT} ${ARGN}) + endif() + + # If Boost_LIBRARY_DIR_[RELEASE,DEBUG] is known then search only there. + if(Boost_LIBRARY_DIR_${build_type}) + set(_boost_LIBRARY_SEARCH_DIRS_${build_type} ${Boost_LIBRARY_DIR_${build_type}} NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH) + _Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" + "Boost_LIBRARY_DIR_${build_type}") + _Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" + "_boost_LIBRARY_SEARCH_DIRS_${build_type}") + endif() +endmacro() + +#------------------------------------------------------------------------------- + +# Convert CMAKE_CXX_COMPILER_VERSION to boost compiler suffix version. +function(_Boost_COMPILER_DUMPVERSION _OUTPUT_VERSION _OUTPUT_VERSION_MAJOR _OUTPUT_VERSION_MINOR) + string(REGEX REPLACE "([0-9]+)\\.([0-9]+)(\\.[0-9]+)?" "\\1" + _boost_COMPILER_VERSION_MAJOR "${CMAKE_CXX_COMPILER_VERSION}") + string(REGEX REPLACE "([0-9]+)\\.([0-9]+)(\\.[0-9]+)?" "\\2" + _boost_COMPILER_VERSION_MINOR "${CMAKE_CXX_COMPILER_VERSION}") + + set(_boost_COMPILER_VERSION "${_boost_COMPILER_VERSION_MAJOR}${_boost_COMPILER_VERSION_MINOR}") + + set(${_OUTPUT_VERSION} ${_boost_COMPILER_VERSION} PARENT_SCOPE) + set(${_OUTPUT_VERSION_MAJOR} ${_boost_COMPILER_VERSION_MAJOR} PARENT_SCOPE) + set(${_OUTPUT_VERSION_MINOR} ${_boost_COMPILER_VERSION_MINOR} PARENT_SCOPE) +endfunction() + +# +# Take a list of libraries with "thread" in it +# and prepend duplicates with "thread_${Boost_THREADAPI}" +# at the front of the list +# +function(_Boost_PREPEND_LIST_WITH_THREADAPI _output) + set(_orig_libnames ${ARGN}) + string(REPLACE "thread" "thread_${Boost_THREADAPI}" _threadapi_libnames "${_orig_libnames}") + set(${_output} ${_threadapi_libnames} ${_orig_libnames} PARENT_SCOPE) +endfunction() + +# +# If a library is found, replace its cache entry with its REALPATH +# +function(_Boost_SWAP_WITH_REALPATH _library _docstring) + if(${_library}) + get_filename_component(_boost_filepathreal ${${_library}} REALPATH) + unset(${_library} CACHE) + set(${_library} ${_boost_filepathreal} CACHE FILEPATH "${_docstring}") + endif() +endfunction() + +function(_Boost_CHECK_SPELLING _var) + if(${_var}) + string(TOUPPER ${_var} _var_UC) + message(FATAL_ERROR "ERROR: ${_var} is not the correct spelling. The proper spelling is ${_var_UC}.") + endif() +endfunction() + +# Guesses Boost's compiler prefix used in built library names +# Returns the guess by setting the variable pointed to by _ret +function(_Boost_GUESS_COMPILER_PREFIX _ret) + if("x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xIntel" + OR "x${CMAKE_CXX_COMPILER_ARCHITECTURE_ID}" STREQUAL "xIntelLLVM") + if(WIN32) + set (_boost_COMPILER "-iw") + else() + set (_boost_COMPILER "-il") + endif() + elseif (GHSMULTI) + set(_boost_COMPILER "-ghs") + elseif("x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xMSVC" OR "x${CMAKE_CXX_SIMULATE_ID}" STREQUAL "xMSVC") + if(MSVC_TOOLSET_VERSION GREATER_EQUAL 150) + # Not yet known. + set(_boost_COMPILER "") + elseif(MSVC_TOOLSET_VERSION GREATER_EQUAL 140) + # MSVC toolset 14.x versions are forward compatible. + set(_boost_COMPILER "") + foreach(v 9 8 7 6 5 4 3 2 1 0) + if(MSVC_TOOLSET_VERSION GREATER_EQUAL 14${v}) + list(APPEND _boost_COMPILER "-vc14${v}") + endif() + endforeach() + elseif(MSVC_TOOLSET_VERSION GREATER_EQUAL 80) + set(_boost_COMPILER "-vc${MSVC_TOOLSET_VERSION}") + elseif(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 13.10) + set(_boost_COMPILER "-vc71") + elseif(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 13) # Good luck! + set(_boost_COMPILER "-vc7") # yes, this is correct + else() # VS 6.0 Good luck! + set(_boost_COMPILER "-vc6") # yes, this is correct + endif() + + if("x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xClang") + string(REPLACE "." ";" VERSION_LIST "${CMAKE_CXX_COMPILER_VERSION}") + list(GET VERSION_LIST 0 CLANG_VERSION_MAJOR) + set(_boost_COMPILER "-clangw${CLANG_VERSION_MAJOR};${_boost_COMPILER}") + endif() + elseif (BORLAND) + set(_boost_COMPILER "-bcb") + elseif(CMAKE_CXX_COMPILER_ID STREQUAL "SunPro") + set(_boost_COMPILER "-sw") + elseif(CMAKE_CXX_COMPILER_ID STREQUAL "XL") + set(_boost_COMPILER "-xlc") + elseif (MINGW) + if(Boost_VERSION_STRING VERSION_LESS 1.34) + set(_boost_COMPILER "-mgw") # no GCC version encoding prior to 1.34 + else() + _Boost_COMPILER_DUMPVERSION(_boost_COMPILER_VERSION _boost_COMPILER_VERSION_MAJOR _boost_COMPILER_VERSION_MINOR) + if(Boost_VERSION_STRING VERSION_GREATER_EQUAL 1.73 AND _boost_COMPILER_VERSION_MAJOR VERSION_GREATER_EQUAL 5) + set(_boost_COMPILER "-mgw${_boost_COMPILER_VERSION_MAJOR}") + else() + set(_boost_COMPILER "-mgw${_boost_COMPILER_VERSION}") + endif() + endif() + elseif (UNIX) + _Boost_COMPILER_DUMPVERSION(_boost_COMPILER_VERSION _boost_COMPILER_VERSION_MAJOR _boost_COMPILER_VERSION_MINOR) + if(NOT Boost_VERSION_STRING VERSION_LESS 1.69.0) + # From GCC 5 and clang 4, versioning changes and minor becomes patch. + # For those compilers, patch is exclude from compiler tag in Boost 1.69+ library naming. + if((CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND _boost_COMPILER_VERSION_MAJOR VERSION_GREATER 4) OR CMAKE_CXX_COMPILER_ID STREQUAL "LCC") + set(_boost_COMPILER_VERSION "${_boost_COMPILER_VERSION_MAJOR}") + elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND _boost_COMPILER_VERSION_MAJOR VERSION_GREATER 3) + set(_boost_COMPILER_VERSION "${_boost_COMPILER_VERSION_MAJOR}") + endif() + endif() + + if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID STREQUAL "LCC") + if(Boost_VERSION_STRING VERSION_LESS 1.34) + set(_boost_COMPILER "-gcc") # no GCC version encoding prior to 1.34 + else() + # Determine which version of GCC we have. + if(APPLE) + if(Boost_VERSION_STRING VERSION_LESS 1.36.0) + # In Boost <= 1.35.0, there is no mangled compiler name for + # the macOS/Darwin version of GCC. + set(_boost_COMPILER "") + else() + # In Boost 1.36.0 and newer, the mangled compiler name used + # on macOS/Darwin is "xgcc". + set(_boost_COMPILER "-xgcc${_boost_COMPILER_VERSION}") + endif() + else() + set(_boost_COMPILER "-gcc${_boost_COMPILER_VERSION}") + endif() + endif() + elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") + # TODO: Find out any Boost version constraints vs clang support. + set(_boost_COMPILER "-clang${_boost_COMPILER_VERSION}") + endif() + else() + set(_boost_COMPILER "") + endif() + _Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" + "_boost_COMPILER" SOURCE "guessed") + set(${_ret} ${_boost_COMPILER} PARENT_SCOPE) +endfunction() + +# +# Get component dependencies. Requires the dependencies to have been +# defined for the Boost release version. +# +# component - the component to check +# _ret - list of library dependencies +# +function(_Boost_COMPONENT_DEPENDENCIES component _ret) + # Note: to add a new Boost release, run + # + # % cmake -DBOOST_DIR=/path/to/boost/source -P Utilities/Scripts/BoostScanDeps.cmake + # + # The output may be added in a new block below. If it's the same as + # the previous release, simply update the version range of the block + # for the previous release. Also check if any new components have + # been added, and add any new components to + # _Boost_COMPONENT_HEADERS. + # + # This information was originally generated by running + # BoostScanDeps.cmake against every boost release to date supported + # by FindBoost: + # + # % for version in /path/to/boost/sources/* + # do + # cmake -DBOOST_DIR=$version -P Utilities/Scripts/BoostScanDeps.cmake + # done + # + # The output was then updated by search and replace with these regexes: + # + # - Strip message(STATUS) prefix dashes + # s;^-- ;; + # - Indent + # s;^set(; set(;; + # - Add conditionals + # s;Scanning /path/to/boost/sources/boost_\(.*\)_\(.*\)_\(.*); elseif(NOT Boost_VERSION_STRING VERSION_LESS \1\.\2\.\3 AND Boost_VERSION_STRING VERSION_LESS xxxx); + # + # This results in the logic seen below, but will require the xxxx + # replacing with the following Boost release version (or the next + # minor version to be released, e.g. 1.59 was the latest at the time + # of writing, making 1.60 the next. Identical consecutive releases + # were then merged together by updating the end range of the first + # block and removing the following redundant blocks. + # + # Running the script against all historical releases should be + # required only if the BoostScanDeps.cmake script logic is changed. + # The addition of a new release should only require it to be run + # against the new release. + + # Handle Python version suffixes + if(component MATCHES "^(python|mpi_python|numpy)([0-9][0-9]?|[0-9]\\.[0-9]+)\$") + set(component "${CMAKE_MATCH_1}") + set(component_python_version "${CMAKE_MATCH_2}") + endif() + + set(_Boost_IMPORTED_TARGETS TRUE) + if(Boost_VERSION_STRING) + if(Boost_VERSION_STRING VERSION_LESS 1.33.0) + message(WARNING "Imported targets and dependency information not available for Boost version ${Boost_VERSION_STRING} (all versions older than 1.33)") + set(_Boost_IMPORTED_TARGETS FALSE) + elseif(Boost_VERSION_STRING VERSION_LESS 1.35.0) + set(_Boost_IOSTREAMS_DEPENDENCIES regex thread) + set(_Boost_REGEX_DEPENDENCIES thread) + set(_Boost_WAVE_DEPENDENCIES filesystem thread) + set(_Boost_WSERIALIZATION_DEPENDENCIES serialization) + elseif(Boost_VERSION_STRING VERSION_LESS 1.36.0) + set(_Boost_FILESYSTEM_DEPENDENCIES system) + set(_Boost_IOSTREAMS_DEPENDENCIES regex) + set(_Boost_MPI_DEPENDENCIES serialization) + set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization) + set(_Boost_WAVE_DEPENDENCIES filesystem system thread) + set(_Boost_WSERIALIZATION_DEPENDENCIES serialization) + elseif(Boost_VERSION_STRING VERSION_LESS 1.38.0) + set(_Boost_FILESYSTEM_DEPENDENCIES system) + set(_Boost_IOSTREAMS_DEPENDENCIES regex) + set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l) + set(_Boost_MPI_DEPENDENCIES serialization) + set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization) + set(_Boost_WAVE_DEPENDENCIES filesystem system thread) + set(_Boost_WSERIALIZATION_DEPENDENCIES serialization) + elseif(Boost_VERSION_STRING VERSION_LESS 1.43.0) + set(_Boost_FILESYSTEM_DEPENDENCIES system) + set(_Boost_IOSTREAMS_DEPENDENCIES regex) + set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l) + set(_Boost_MPI_DEPENDENCIES serialization) + set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization) + set(_Boost_THREAD_DEPENDENCIES date_time) + set(_Boost_WAVE_DEPENDENCIES filesystem system thread date_time) + set(_Boost_WSERIALIZATION_DEPENDENCIES serialization) + elseif(Boost_VERSION_STRING VERSION_LESS 1.44.0) + set(_Boost_FILESYSTEM_DEPENDENCIES system) + set(_Boost_IOSTREAMS_DEPENDENCIES regex) + set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l random) + set(_Boost_MPI_DEPENDENCIES serialization) + set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization) + set(_Boost_THREAD_DEPENDENCIES date_time) + set(_Boost_WAVE_DEPENDENCIES filesystem system thread date_time) + set(_Boost_WSERIALIZATION_DEPENDENCIES serialization) + elseif(Boost_VERSION_STRING VERSION_LESS 1.45.0) + set(_Boost_FILESYSTEM_DEPENDENCIES system) + set(_Boost_IOSTREAMS_DEPENDENCIES regex) + set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l random serialization) + set(_Boost_MPI_DEPENDENCIES serialization) + set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization) + set(_Boost_THREAD_DEPENDENCIES date_time) + set(_Boost_WAVE_DEPENDENCIES serialization filesystem system thread date_time) + set(_Boost_WSERIALIZATION_DEPENDENCIES serialization) + elseif(Boost_VERSION_STRING VERSION_LESS 1.47.0) + set(_Boost_FILESYSTEM_DEPENDENCIES system) + set(_Boost_IOSTREAMS_DEPENDENCIES regex) + set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l random) + set(_Boost_MPI_DEPENDENCIES serialization) + set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization) + set(_Boost_THREAD_DEPENDENCIES date_time) + set(_Boost_WAVE_DEPENDENCIES filesystem system serialization thread date_time) + set(_Boost_WSERIALIZATION_DEPENDENCIES serialization) + elseif(Boost_VERSION_STRING VERSION_LESS 1.48.0) + set(_Boost_CHRONO_DEPENDENCIES system) + set(_Boost_FILESYSTEM_DEPENDENCIES system) + set(_Boost_IOSTREAMS_DEPENDENCIES regex) + set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l random) + set(_Boost_MPI_DEPENDENCIES serialization) + set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization) + set(_Boost_THREAD_DEPENDENCIES date_time) + set(_Boost_WAVE_DEPENDENCIES filesystem system serialization thread date_time) + set(_Boost_WSERIALIZATION_DEPENDENCIES serialization) + elseif(Boost_VERSION_STRING VERSION_LESS 1.50.0) + set(_Boost_CHRONO_DEPENDENCIES system) + set(_Boost_FILESYSTEM_DEPENDENCIES system) + set(_Boost_IOSTREAMS_DEPENDENCIES regex) + set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l random) + set(_Boost_MPI_DEPENDENCIES serialization) + set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization) + set(_Boost_THREAD_DEPENDENCIES date_time) + set(_Boost_TIMER_DEPENDENCIES chrono system) + set(_Boost_WAVE_DEPENDENCIES filesystem system serialization thread date_time) + set(_Boost_WSERIALIZATION_DEPENDENCIES serialization) + elseif(Boost_VERSION_STRING VERSION_LESS 1.53.0) + set(_Boost_CHRONO_DEPENDENCIES system) + set(_Boost_FILESYSTEM_DEPENDENCIES system) + set(_Boost_IOSTREAMS_DEPENDENCIES regex) + set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l regex random) + set(_Boost_MPI_DEPENDENCIES serialization) + set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization) + set(_Boost_THREAD_DEPENDENCIES chrono system date_time) + set(_Boost_TIMER_DEPENDENCIES chrono system) + set(_Boost_WAVE_DEPENDENCIES filesystem system serialization thread chrono date_time) + set(_Boost_WSERIALIZATION_DEPENDENCIES serialization) + elseif(Boost_VERSION_STRING VERSION_LESS 1.54.0) + set(_Boost_ATOMIC_DEPENDENCIES thread chrono system date_time) + set(_Boost_CHRONO_DEPENDENCIES system) + set(_Boost_FILESYSTEM_DEPENDENCIES system) + set(_Boost_IOSTREAMS_DEPENDENCIES regex) + set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l regex random) + set(_Boost_MPI_DEPENDENCIES serialization) + set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization) + set(_Boost_THREAD_DEPENDENCIES chrono system date_time atomic) + set(_Boost_TIMER_DEPENDENCIES chrono system) + set(_Boost_WAVE_DEPENDENCIES filesystem system serialization thread chrono date_time) + set(_Boost_WSERIALIZATION_DEPENDENCIES serialization) + elseif(Boost_VERSION_STRING VERSION_LESS 1.55.0) + set(_Boost_ATOMIC_DEPENDENCIES thread chrono system date_time) + set(_Boost_CHRONO_DEPENDENCIES system) + set(_Boost_FILESYSTEM_DEPENDENCIES system) + set(_Boost_IOSTREAMS_DEPENDENCIES regex) + set(_Boost_LOG_DEPENDENCIES log_setup date_time system filesystem thread regex chrono) + set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l regex random) + set(_Boost_MPI_DEPENDENCIES serialization) + set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization) + set(_Boost_THREAD_DEPENDENCIES chrono system date_time atomic) + set(_Boost_TIMER_DEPENDENCIES chrono system) + set(_Boost_WAVE_DEPENDENCIES filesystem system serialization thread chrono date_time atomic) + set(_Boost_WSERIALIZATION_DEPENDENCIES serialization) + elseif(Boost_VERSION_STRING VERSION_LESS 1.56.0) + set(_Boost_CHRONO_DEPENDENCIES system) + set(_Boost_COROUTINE_DEPENDENCIES context system) + set(_Boost_FILESYSTEM_DEPENDENCIES system) + set(_Boost_IOSTREAMS_DEPENDENCIES regex) + set(_Boost_LOG_DEPENDENCIES log_setup date_time system filesystem thread regex chrono) + set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l regex random) + set(_Boost_MPI_DEPENDENCIES serialization) + set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization) + set(_Boost_THREAD_DEPENDENCIES chrono system date_time atomic) + set(_Boost_TIMER_DEPENDENCIES chrono system) + set(_Boost_WAVE_DEPENDENCIES filesystem system serialization thread chrono date_time atomic) + set(_Boost_WSERIALIZATION_DEPENDENCIES serialization) + elseif(Boost_VERSION_STRING VERSION_LESS 1.59.0) + set(_Boost_CHRONO_DEPENDENCIES system) + set(_Boost_COROUTINE_DEPENDENCIES context system) + set(_Boost_FILESYSTEM_DEPENDENCIES system) + set(_Boost_IOSTREAMS_DEPENDENCIES regex) + set(_Boost_LOG_DEPENDENCIES log_setup date_time system filesystem thread regex chrono) + set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l atomic) + set(_Boost_MPI_DEPENDENCIES serialization) + set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization) + set(_Boost_RANDOM_DEPENDENCIES system) + set(_Boost_THREAD_DEPENDENCIES chrono system date_time atomic) + set(_Boost_TIMER_DEPENDENCIES chrono system) + set(_Boost_WAVE_DEPENDENCIES filesystem system serialization thread chrono date_time atomic) + set(_Boost_WSERIALIZATION_DEPENDENCIES serialization) + elseif(Boost_VERSION_STRING VERSION_LESS 1.60.0) + set(_Boost_CHRONO_DEPENDENCIES system) + set(_Boost_COROUTINE_DEPENDENCIES context system) + set(_Boost_FILESYSTEM_DEPENDENCIES system) + set(_Boost_IOSTREAMS_DEPENDENCIES regex) + set(_Boost_LOG_DEPENDENCIES log_setup date_time system filesystem thread regex chrono atomic) + set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l atomic) + set(_Boost_MPI_DEPENDENCIES serialization) + set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization) + set(_Boost_RANDOM_DEPENDENCIES system) + set(_Boost_THREAD_DEPENDENCIES chrono system date_time atomic) + set(_Boost_TIMER_DEPENDENCIES chrono system) + set(_Boost_WAVE_DEPENDENCIES filesystem system serialization thread chrono date_time atomic) + set(_Boost_WSERIALIZATION_DEPENDENCIES serialization) + elseif(Boost_VERSION_STRING VERSION_LESS 1.61.0) + set(_Boost_CHRONO_DEPENDENCIES system) + set(_Boost_COROUTINE_DEPENDENCIES context system) + set(_Boost_FILESYSTEM_DEPENDENCIES system) + set(_Boost_IOSTREAMS_DEPENDENCIES regex) + set(_Boost_LOG_DEPENDENCIES date_time log_setup system filesystem thread regex chrono atomic) + set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l atomic) + set(_Boost_MPI_DEPENDENCIES serialization) + set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization) + set(_Boost_RANDOM_DEPENDENCIES system) + set(_Boost_THREAD_DEPENDENCIES chrono system date_time atomic) + set(_Boost_TIMER_DEPENDENCIES chrono system) + set(_Boost_WAVE_DEPENDENCIES filesystem system serialization thread chrono date_time atomic) + set(_Boost_WSERIALIZATION_DEPENDENCIES serialization) + elseif(Boost_VERSION_STRING VERSION_LESS 1.62.0) + set(_Boost_CHRONO_DEPENDENCIES system) + set(_Boost_CONTEXT_DEPENDENCIES thread chrono system date_time) + set(_Boost_COROUTINE_DEPENDENCIES context system) + set(_Boost_FILESYSTEM_DEPENDENCIES system) + set(_Boost_IOSTREAMS_DEPENDENCIES regex) + set(_Boost_LOG_DEPENDENCIES date_time log_setup system filesystem thread regex chrono atomic) + set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l atomic) + set(_Boost_MPI_DEPENDENCIES serialization) + set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization) + set(_Boost_RANDOM_DEPENDENCIES system) + set(_Boost_THREAD_DEPENDENCIES chrono system date_time atomic) + set(_Boost_WAVE_DEPENDENCIES filesystem system serialization thread chrono date_time atomic) + set(_Boost_WSERIALIZATION_DEPENDENCIES serialization) + elseif(Boost_VERSION_STRING VERSION_LESS 1.63.0) + set(_Boost_CHRONO_DEPENDENCIES system) + set(_Boost_CONTEXT_DEPENDENCIES thread chrono system date_time) + set(_Boost_COROUTINE_DEPENDENCIES context system) + set(_Boost_FIBER_DEPENDENCIES context thread chrono system date_time) + set(_Boost_FILESYSTEM_DEPENDENCIES system) + set(_Boost_IOSTREAMS_DEPENDENCIES regex) + set(_Boost_LOG_DEPENDENCIES date_time log_setup system filesystem thread regex chrono atomic) + set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l atomic) + set(_Boost_MPI_DEPENDENCIES serialization) + set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization) + set(_Boost_RANDOM_DEPENDENCIES system) + set(_Boost_THREAD_DEPENDENCIES chrono system date_time atomic) + set(_Boost_WAVE_DEPENDENCIES filesystem system serialization thread chrono date_time atomic) + set(_Boost_WSERIALIZATION_DEPENDENCIES serialization) + elseif(Boost_VERSION_STRING VERSION_LESS 1.65.0) + set(_Boost_CHRONO_DEPENDENCIES system) + set(_Boost_CONTEXT_DEPENDENCIES thread chrono system date_time) + set(_Boost_COROUTINE_DEPENDENCIES context system) + set(_Boost_COROUTINE2_DEPENDENCIES context fiber thread chrono system date_time) + set(_Boost_FIBER_DEPENDENCIES context thread chrono system date_time) + set(_Boost_FILESYSTEM_DEPENDENCIES system) + set(_Boost_IOSTREAMS_DEPENDENCIES regex) + set(_Boost_LOG_DEPENDENCIES date_time log_setup system filesystem thread regex chrono atomic) + set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l atomic) + set(_Boost_MPI_DEPENDENCIES serialization) + set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization) + set(_Boost_RANDOM_DEPENDENCIES system) + set(_Boost_THREAD_DEPENDENCIES chrono system date_time atomic) + set(_Boost_WAVE_DEPENDENCIES filesystem system serialization thread chrono date_time atomic) + set(_Boost_WSERIALIZATION_DEPENDENCIES serialization) + elseif(Boost_VERSION_STRING VERSION_LESS 1.67.0) + set(_Boost_CHRONO_DEPENDENCIES system) + set(_Boost_CONTEXT_DEPENDENCIES thread chrono system date_time) + set(_Boost_COROUTINE_DEPENDENCIES context system) + set(_Boost_FIBER_DEPENDENCIES context thread chrono system date_time) + set(_Boost_FILESYSTEM_DEPENDENCIES system) + set(_Boost_IOSTREAMS_DEPENDENCIES regex) + set(_Boost_LOG_DEPENDENCIES date_time log_setup system filesystem thread regex chrono atomic) + set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l atomic) + set(_Boost_MPI_DEPENDENCIES serialization) + set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization) + set(_Boost_NUMPY_DEPENDENCIES python${component_python_version}) + set(_Boost_RANDOM_DEPENDENCIES system) + set(_Boost_THREAD_DEPENDENCIES chrono system date_time atomic) + set(_Boost_TIMER_DEPENDENCIES chrono system) + set(_Boost_WAVE_DEPENDENCIES filesystem system serialization thread chrono date_time atomic) + set(_Boost_WSERIALIZATION_DEPENDENCIES serialization) + elseif(Boost_VERSION_STRING VERSION_LESS 1.68.0) + set(_Boost_CHRONO_DEPENDENCIES system) + set(_Boost_CONTEXT_DEPENDENCIES thread chrono system date_time) + set(_Boost_COROUTINE_DEPENDENCIES context system) + set(_Boost_FIBER_DEPENDENCIES context thread chrono system date_time) + set(_Boost_FILESYSTEM_DEPENDENCIES system) + set(_Boost_IOSTREAMS_DEPENDENCIES regex) + set(_Boost_LOG_DEPENDENCIES date_time log_setup system filesystem thread regex chrono atomic) + set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l atomic) + set(_Boost_MPI_DEPENDENCIES serialization) + set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization) + set(_Boost_NUMPY_DEPENDENCIES python${component_python_version}) + set(_Boost_RANDOM_DEPENDENCIES system) + set(_Boost_THREAD_DEPENDENCIES chrono system date_time atomic) + set(_Boost_TIMER_DEPENDENCIES chrono system) + set(_Boost_WAVE_DEPENDENCIES filesystem system serialization thread chrono date_time atomic) + set(_Boost_WSERIALIZATION_DEPENDENCIES serialization) + elseif(Boost_VERSION_STRING VERSION_LESS 1.69.0) + set(_Boost_CHRONO_DEPENDENCIES system) + set(_Boost_CONTEXT_DEPENDENCIES thread chrono system date_time) + set(_Boost_CONTRACT_DEPENDENCIES thread chrono system date_time) + set(_Boost_COROUTINE_DEPENDENCIES context system) + set(_Boost_FIBER_DEPENDENCIES context thread chrono system date_time) + set(_Boost_FILESYSTEM_DEPENDENCIES system) + set(_Boost_IOSTREAMS_DEPENDENCIES regex) + set(_Boost_LOG_DEPENDENCIES date_time log_setup system filesystem thread regex chrono atomic) + set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l atomic) + set(_Boost_MPI_DEPENDENCIES serialization) + set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization) + set(_Boost_NUMPY_DEPENDENCIES python${component_python_version}) + set(_Boost_RANDOM_DEPENDENCIES system) + set(_Boost_THREAD_DEPENDENCIES chrono system date_time atomic) + set(_Boost_TIMER_DEPENDENCIES chrono system) + set(_Boost_WAVE_DEPENDENCIES filesystem system serialization thread chrono date_time atomic) + set(_Boost_WSERIALIZATION_DEPENDENCIES serialization) + elseif(Boost_VERSION_STRING VERSION_LESS 1.70.0) + set(_Boost_CONTRACT_DEPENDENCIES thread chrono date_time) + set(_Boost_COROUTINE_DEPENDENCIES context) + set(_Boost_FIBER_DEPENDENCIES context) + set(_Boost_IOSTREAMS_DEPENDENCIES regex) + set(_Boost_LOG_DEPENDENCIES date_time log_setup filesystem thread regex chrono atomic) + set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l atomic) + set(_Boost_MPI_DEPENDENCIES serialization) + set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization) + set(_Boost_NUMPY_DEPENDENCIES python${component_python_version}) + set(_Boost_THREAD_DEPENDENCIES chrono date_time atomic) + set(_Boost_TIMER_DEPENDENCIES chrono system) + set(_Boost_WAVE_DEPENDENCIES filesystem serialization thread chrono date_time atomic) + set(_Boost_WSERIALIZATION_DEPENDENCIES serialization) + elseif(Boost_VERSION_STRING VERSION_LESS 1.72.0) + set(_Boost_CONTRACT_DEPENDENCIES thread chrono date_time) + set(_Boost_COROUTINE_DEPENDENCIES context) + set(_Boost_FIBER_DEPENDENCIES context) + set(_Boost_IOSTREAMS_DEPENDENCIES regex) + set(_Boost_LOG_DEPENDENCIES date_time log_setup filesystem thread regex chrono atomic) + set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l atomic) + set(_Boost_MPI_DEPENDENCIES serialization) + set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization) + set(_Boost_NUMPY_DEPENDENCIES python${component_python_version}) + set(_Boost_THREAD_DEPENDENCIES chrono date_time atomic) + set(_Boost_TIMER_DEPENDENCIES chrono) + set(_Boost_WAVE_DEPENDENCIES filesystem serialization thread chrono date_time atomic) + set(_Boost_WSERIALIZATION_DEPENDENCIES serialization) + elseif(Boost_VERSION_STRING VERSION_LESS 1.73.0) + set(_Boost_CONTRACT_DEPENDENCIES thread chrono date_time) + set(_Boost_COROUTINE_DEPENDENCIES context) + set(_Boost_FIBER_DEPENDENCIES context) + set(_Boost_IOSTREAMS_DEPENDENCIES regex) + set(_Boost_LOG_DEPENDENCIES date_time log_setup filesystem thread regex chrono atomic) + set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l chrono atomic) + set(_Boost_MPI_DEPENDENCIES serialization) + set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization) + set(_Boost_NUMPY_DEPENDENCIES python${component_python_version}) + set(_Boost_THREAD_DEPENDENCIES chrono date_time atomic) + set(_Boost_TIMER_DEPENDENCIES chrono) + set(_Boost_WAVE_DEPENDENCIES filesystem serialization thread chrono date_time atomic) + set(_Boost_WSERIALIZATION_DEPENDENCIES serialization) + elseif(Boost_VERSION_STRING VERSION_LESS 1.75.0) + set(_Boost_CONTRACT_DEPENDENCIES thread chrono date_time) + set(_Boost_COROUTINE_DEPENDENCIES context) + set(_Boost_FIBER_DEPENDENCIES context) + set(_Boost_IOSTREAMS_DEPENDENCIES regex) + set(_Boost_LOG_DEPENDENCIES date_time log_setup filesystem thread regex chrono atomic) + set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l atomic) + set(_Boost_MPI_DEPENDENCIES serialization) + set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization) + set(_Boost_NUMPY_DEPENDENCIES python${component_python_version}) + set(_Boost_THREAD_DEPENDENCIES chrono date_time atomic) + set(_Boost_TIMER_DEPENDENCIES chrono) + set(_Boost_WAVE_DEPENDENCIES filesystem serialization thread chrono date_time atomic) + set(_Boost_WSERIALIZATION_DEPENDENCIES serialization) + elseif(Boost_VERSION_STRING VERSION_LESS 1.77.0) + set(_Boost_CONTRACT_DEPENDENCIES thread chrono date_time) + set(_Boost_COROUTINE_DEPENDENCIES context) + set(_Boost_FIBER_DEPENDENCIES context) + set(_Boost_IOSTREAMS_DEPENDENCIES regex) + set(_Boost_JSON_DEPENDENCIES container) + set(_Boost_LOG_DEPENDENCIES date_time log_setup filesystem thread regex chrono atomic) + set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l atomic) + set(_Boost_MPI_DEPENDENCIES serialization) + set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization) + set(_Boost_NUMPY_DEPENDENCIES python${component_python_version}) + set(_Boost_THREAD_DEPENDENCIES chrono date_time atomic) + set(_Boost_TIMER_DEPENDENCIES chrono) + set(_Boost_WAVE_DEPENDENCIES filesystem serialization thread chrono date_time atomic) + set(_Boost_WSERIALIZATION_DEPENDENCIES serialization) + elseif(Boost_VERSION_STRING VERSION_LESS 1.78.0) + set(_Boost_CONTRACT_DEPENDENCIES thread chrono) + set(_Boost_COROUTINE_DEPENDENCIES context) + set(_Boost_FIBER_DEPENDENCIES context) + set(_Boost_IOSTREAMS_DEPENDENCIES regex) + set(_Boost_JSON_DEPENDENCIES container) + set(_Boost_LOG_DEPENDENCIES date_time log_setup filesystem thread regex chrono atomic) + set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l) + set(_Boost_MPI_DEPENDENCIES serialization) + set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization) + set(_Boost_NUMPY_DEPENDENCIES python${component_python_version}) + set(_Boost_THREAD_DEPENDENCIES chrono atomic) + set(_Boost_TIMER_DEPENDENCIES chrono) + set(_Boost_WAVE_DEPENDENCIES filesystem serialization thread chrono atomic) + set(_Boost_WSERIALIZATION_DEPENDENCIES serialization) + else() + set(_Boost_CONTRACT_DEPENDENCIES thread chrono) + set(_Boost_COROUTINE_DEPENDENCIES context) + set(_Boost_FIBER_DEPENDENCIES context) + set(_Boost_IOSTREAMS_DEPENDENCIES regex) + set(_Boost_JSON_DEPENDENCIES container) + set(_Boost_LOG_DEPENDENCIES log_setup filesystem thread regex chrono atomic) + set(_Boost_MATH_DEPENDENCIES math_c99 math_c99f math_c99l math_tr1 math_tr1f math_tr1l) + set(_Boost_MPI_DEPENDENCIES serialization) + set(_Boost_MPI_PYTHON_DEPENDENCIES python${component_python_version} mpi serialization) + set(_Boost_NUMPY_DEPENDENCIES python${component_python_version}) + set(_Boost_THREAD_DEPENDENCIES chrono atomic) + set(_Boost_TIMER_DEPENDENCIES chrono) + set(_Boost_WAVE_DEPENDENCIES filesystem serialization thread chrono atomic) + set(_Boost_WSERIALIZATION_DEPENDENCIES serialization) + if(Boost_VERSION_STRING VERSION_GREATER_EQUAL 1.82.0 AND NOT Boost_NO_WARN_NEW_VERSIONS) + message(WARNING "New Boost version may have incorrect or missing dependencies and imported targets") + endif() + endif() + endif() + + string(TOUPPER ${component} uppercomponent) + set(${_ret} ${_Boost_${uppercomponent}_DEPENDENCIES} PARENT_SCOPE) + set(_Boost_IMPORTED_TARGETS ${_Boost_IMPORTED_TARGETS} PARENT_SCOPE) + + string(REGEX REPLACE ";" " " _boost_DEPS_STRING "${_Boost_${uppercomponent}_DEPENDENCIES}") + if (NOT _boost_DEPS_STRING) + set(_boost_DEPS_STRING "(none)") + endif() + # message(STATUS "Dependencies for Boost::${component}: ${_boost_DEPS_STRING}") +endfunction() + +# +# Get component headers. This is the primary header (or headers) for +# a given component, and is used to check that the headers are present +# as well as the library itself as an extra sanity check of the build +# environment. +# +# component - the component to check +# _hdrs +# +function(_Boost_COMPONENT_HEADERS component _hdrs) + # Handle Python version suffixes + if(component MATCHES "^(python|mpi_python|numpy)([0-9]+|[0-9]\\.[0-9]+)\$") + set(component "${CMAKE_MATCH_1}") + set(component_python_version "${CMAKE_MATCH_2}") + endif() + + # Note: new boost components will require adding here. The header + # must be present in all versions of Boost providing a library. + set(_Boost_ATOMIC_HEADERS "boost/atomic.hpp") + set(_Boost_CHRONO_HEADERS "boost/chrono.hpp") + set(_Boost_CONTAINER_HEADERS "boost/container/container_fwd.hpp") + set(_Boost_CONTRACT_HEADERS "boost/contract.hpp") + if(Boost_VERSION_STRING VERSION_LESS 1.61.0) + set(_Boost_CONTEXT_HEADERS "boost/context/all.hpp") + else() + set(_Boost_CONTEXT_HEADERS "boost/context/detail/fcontext.hpp") + endif() + set(_Boost_COROUTINE_HEADERS "boost/coroutine/all.hpp") + set(_Boost_DATE_TIME_HEADERS "boost/date_time/date.hpp") + set(_Boost_EXCEPTION_HEADERS "boost/exception/exception.hpp") + set(_Boost_FIBER_HEADERS "boost/fiber/all.hpp") + set(_Boost_FILESYSTEM_HEADERS "boost/filesystem/path.hpp") + set(_Boost_GRAPH_HEADERS "boost/graph/adjacency_list.hpp") + set(_Boost_GRAPH_PARALLEL_HEADERS "boost/graph/adjacency_list.hpp") + set(_Boost_IOSTREAMS_HEADERS "boost/iostreams/stream.hpp") + set(_Boost_LOCALE_HEADERS "boost/locale.hpp") + set(_Boost_LOG_HEADERS "boost/log/core.hpp") + set(_Boost_LOG_SETUP_HEADERS "boost/log/detail/setup_config.hpp") + set(_Boost_JSON_HEADERS "boost/json.hpp") + set(_Boost_MATH_HEADERS "boost/math_fwd.hpp") + set(_Boost_MATH_C99_HEADERS "boost/math/tr1.hpp") + set(_Boost_MATH_C99F_HEADERS "boost/math/tr1.hpp") + set(_Boost_MATH_C99L_HEADERS "boost/math/tr1.hpp") + set(_Boost_MATH_TR1_HEADERS "boost/math/tr1.hpp") + set(_Boost_MATH_TR1F_HEADERS "boost/math/tr1.hpp") + set(_Boost_MATH_TR1L_HEADERS "boost/math/tr1.hpp") + set(_Boost_MPI_HEADERS "boost/mpi.hpp") + set(_Boost_MPI_PYTHON_HEADERS "boost/mpi/python/config.hpp") + set(_Boost_NUMPY_HEADERS "boost/python/numpy.hpp") + set(_Boost_NOWIDE_HEADERS "boost/nowide/cstdlib.hpp") + set(_Boost_PRG_EXEC_MONITOR_HEADERS "boost/test/prg_exec_monitor.hpp") + set(_Boost_PROGRAM_OPTIONS_HEADERS "boost/program_options.hpp") + set(_Boost_PYTHON_HEADERS "boost/python.hpp") + set(_Boost_RANDOM_HEADERS "boost/random.hpp") + set(_Boost_REGEX_HEADERS "boost/regex.hpp") + set(_Boost_SERIALIZATION_HEADERS "boost/serialization/serialization.hpp") + set(_Boost_SIGNALS_HEADERS "boost/signals.hpp") + set(_Boost_STACKTRACE_ADDR2LINE_HEADERS "boost/stacktrace.hpp") + set(_Boost_STACKTRACE_BACKTRACE_HEADERS "boost/stacktrace.hpp") + set(_Boost_STACKTRACE_BASIC_HEADERS "boost/stacktrace.hpp") + set(_Boost_STACKTRACE_NOOP_HEADERS "boost/stacktrace.hpp") + set(_Boost_STACKTRACE_WINDBG_CACHED_HEADERS "boost/stacktrace.hpp") + set(_Boost_STACKTRACE_WINDBG_HEADERS "boost/stacktrace.hpp") + set(_Boost_SYSTEM_HEADERS "boost/system/config.hpp") + set(_Boost_TEST_EXEC_MONITOR_HEADERS "boost/test/test_exec_monitor.hpp") + set(_Boost_THREAD_HEADERS "boost/thread.hpp") + set(_Boost_TIMER_HEADERS "boost/timer.hpp") + set(_Boost_TYPE_ERASURE_HEADERS "boost/type_erasure/config.hpp") + set(_Boost_UNIT_TEST_FRAMEWORK_HEADERS "boost/test/framework.hpp") + set(_Boost_URL_HEADERS "boost/url.hpp") + set(_Boost_WAVE_HEADERS "boost/wave.hpp") + set(_Boost_WSERIALIZATION_HEADERS "boost/archive/text_wiarchive.hpp") + set(_Boost_BZIP2_HEADERS "boost/iostreams/filter/bzip2.hpp") + set(_Boost_ZLIB_HEADERS "boost/iostreams/filter/zlib.hpp") + + string(TOUPPER ${component} uppercomponent) + set(${_hdrs} ${_Boost_${uppercomponent}_HEADERS} PARENT_SCOPE) + + string(REGEX REPLACE ";" " " _boost_HDRS_STRING "${_Boost_${uppercomponent}_HEADERS}") + if (NOT _boost_HDRS_STRING) + set(_boost_HDRS_STRING "(none)") + endif() + # message(STATUS "Headers for Boost::${component}: ${_boost_HDRS_STRING}") +endfunction() + +# +# Determine if any missing dependencies require adding to the component list. +# +# Sets _Boost_${COMPONENT}_DEPENDENCIES for each required component, +# plus _Boost_IMPORTED_TARGETS (TRUE if imported targets should be +# defined; FALSE if dependency information is unavailable). +# +# componentvar - the component list variable name +# extravar - the indirect dependency list variable name +# +# +function(_Boost_MISSING_DEPENDENCIES componentvar extravar) + # _boost_unprocessed_components - list of components requiring processing + # _boost_processed_components - components already processed (or currently being processed) + # _boost_new_components - new components discovered for future processing + # + list(APPEND _boost_unprocessed_components ${${componentvar}}) + + while(_boost_unprocessed_components) + list(APPEND _boost_processed_components ${_boost_unprocessed_components}) + foreach(component ${_boost_unprocessed_components}) + string(TOUPPER ${component} uppercomponent) + set(${_ret} ${_Boost_${uppercomponent}_DEPENDENCIES} PARENT_SCOPE) + _Boost_COMPONENT_DEPENDENCIES("${component}" _Boost_${uppercomponent}_DEPENDENCIES) + set(_Boost_${uppercomponent}_DEPENDENCIES ${_Boost_${uppercomponent}_DEPENDENCIES} PARENT_SCOPE) + set(_Boost_IMPORTED_TARGETS ${_Boost_IMPORTED_TARGETS} PARENT_SCOPE) + foreach(componentdep ${_Boost_${uppercomponent}_DEPENDENCIES}) + if (NOT ("${componentdep}" IN_LIST _boost_processed_components OR "${componentdep}" IN_LIST _boost_new_components)) + list(APPEND _boost_new_components ${componentdep}) + endif() + endforeach() + endforeach() + set(_boost_unprocessed_components ${_boost_new_components}) + unset(_boost_new_components) + endwhile() + set(_boost_extra_components ${_boost_processed_components}) + if(_boost_extra_components AND ${componentvar}) + list(REMOVE_ITEM _boost_extra_components ${${componentvar}}) + endif() + set(${componentvar} ${_boost_processed_components} PARENT_SCOPE) + set(${extravar} ${_boost_extra_components} PARENT_SCOPE) +endfunction() + +# +# Some boost libraries may require particular set of compler features. +# The very first one was `boost::fiber` introduced in Boost 1.62. +# One can check required compiler features of it in +# - `${Boost_ROOT}/libs/fiber/build/Jamfile.v2`; +# - `${Boost_ROOT}/libs/context/build/Jamfile.v2`. +# +# TODO (Re)Check compiler features on (every?) release ??? +# One may use the following command to get the files to check: +# +# $ find . -name Jamfile.v2 | grep build | xargs grep -l cxx1 +# +function(_Boost_COMPILER_FEATURES component _ret) + # Boost >= 1.62 + if(NOT Boost_VERSION_STRING VERSION_LESS 1.62.0) + set(_Boost_FIBER_COMPILER_FEATURES + cxx_alias_templates + cxx_auto_type + cxx_constexpr + cxx_defaulted_functions + cxx_final + cxx_lambdas + cxx_noexcept + cxx_nullptr + cxx_rvalue_references + cxx_thread_local + cxx_variadic_templates + ) + # Compiler feature for `context` same as for `fiber`. + set(_Boost_CONTEXT_COMPILER_FEATURES ${_Boost_FIBER_COMPILER_FEATURES}) + endif() + + # Boost Contract library available in >= 1.67 + if(NOT Boost_VERSION_STRING VERSION_LESS 1.67.0) + # From `libs/contract/build/boost_contract_build.jam` + set(_Boost_CONTRACT_COMPILER_FEATURES + cxx_lambdas + cxx_variadic_templates + ) + endif() + + string(TOUPPER ${component} uppercomponent) + set(${_ret} ${_Boost_${uppercomponent}_COMPILER_FEATURES} PARENT_SCOPE) +endfunction() + +# +# Update library search directory hint variable with paths used by prebuilt boost binaries. +# +# Prebuilt windows binaries (https://sourceforge.net/projects/boost/files/boost-binaries/) +# have library directories named using MSVC compiler version and architecture. +# This function would append corresponding directories if MSVC is a current compiler, +# so having `BOOST_ROOT` would be enough to specify to find everything. +# +function(_Boost_UPDATE_WINDOWS_LIBRARY_SEARCH_DIRS_WITH_PREBUILT_PATHS componentlibvar basedir) + if("x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xMSVC") + if(CMAKE_SIZEOF_VOID_P EQUAL 8) + set(_arch_suffix 64) + else() + set(_arch_suffix 32) + endif() + if(MSVC_TOOLSET_VERSION GREATER_EQUAL 150) + # Not yet known. + elseif(MSVC_TOOLSET_VERSION GREATER_EQUAL 140) + # MSVC toolset 14.x versions are forward compatible. + foreach(v 9 8 7 6 5 4 3 2 1 0) + if(MSVC_TOOLSET_VERSION GREATER_EQUAL 14${v}) + list(APPEND ${componentlibvar} ${basedir}/lib${_arch_suffix}-msvc-14.${v}) + endif() + endforeach() + elseif(MSVC_TOOLSET_VERSION GREATER_EQUAL 80) + math(EXPR _toolset_major_version "${MSVC_TOOLSET_VERSION} / 10") + list(APPEND ${componentlibvar} ${basedir}/lib${_arch_suffix}-msvc-${_toolset_major_version}.0) + endif() + set(${componentlibvar} ${${componentlibvar}} PARENT_SCOPE) + endif() +endfunction() + +# +# End functions/macros +# +#------------------------------------------------------------------------------- + +#------------------------------------------------------------------------------- +# main. +#------------------------------------------------------------------------------- + + +# If the user sets Boost_LIBRARY_DIR, use it as the default for both +# configurations. +if(NOT Boost_LIBRARY_DIR_RELEASE AND Boost_LIBRARY_DIR) + set(Boost_LIBRARY_DIR_RELEASE "${Boost_LIBRARY_DIR}") +endif() +if(NOT Boost_LIBRARY_DIR_DEBUG AND Boost_LIBRARY_DIR) + set(Boost_LIBRARY_DIR_DEBUG "${Boost_LIBRARY_DIR}") +endif() + +if(NOT DEFINED Boost_USE_DEBUG_LIBS) + set(Boost_USE_DEBUG_LIBS TRUE) +endif() +if(NOT DEFINED Boost_USE_RELEASE_LIBS) + set(Boost_USE_RELEASE_LIBS TRUE) +endif() +if(NOT DEFINED Boost_USE_MULTITHREADED) + set(Boost_USE_MULTITHREADED TRUE) +endif() +if(NOT DEFINED Boost_USE_DEBUG_RUNTIME) + set(Boost_USE_DEBUG_RUNTIME TRUE) +endif() + +# Check the version of Boost against the requested version. +if(Boost_FIND_VERSION AND NOT Boost_FIND_VERSION_MINOR) + message(SEND_ERROR "When requesting a specific version of Boost, you must provide at least the major and minor version numbers, e.g., 1.34") +endif() + +if(Boost_FIND_VERSION_EXACT) + # The version may appear in a directory with or without the patch + # level, even when the patch level is non-zero. + set(_boost_TEST_VERSIONS + "${Boost_FIND_VERSION_MAJOR}.${Boost_FIND_VERSION_MINOR}.${Boost_FIND_VERSION_PATCH}" + "${Boost_FIND_VERSION_MAJOR}.${Boost_FIND_VERSION_MINOR}") +else() + # The user has not requested an exact version. Among known + # versions, find those that are acceptable to the user request. + # + # Note: When adding a new Boost release, also update the dependency + # information in _Boost_COMPONENT_DEPENDENCIES and + # _Boost_COMPONENT_HEADERS. See the instructions at the top of + # _Boost_COMPONENT_DEPENDENCIES. + set(_Boost_KNOWN_VERSIONS ${Boost_ADDITIONAL_VERSIONS} + "1.81.0" "1.81" "1.80.0" "1.80" "1.79.0" "1.79" + "1.78.0" "1.78" "1.77.0" "1.77" "1.76.0" "1.76" "1.75.0" "1.75" "1.74.0" "1.74" + "1.73.0" "1.73" "1.72.0" "1.72" "1.71.0" "1.71" "1.70.0" "1.70" "1.69.0" "1.69" + "1.68.0" "1.68" "1.67.0" "1.67" "1.66.0" "1.66" "1.65.1" "1.65.0" "1.65" + "1.64.0" "1.64" "1.63.0" "1.63" "1.62.0" "1.62" "1.61.0" "1.61" "1.60.0" "1.60" + "1.59.0" "1.59" "1.58.0" "1.58" "1.57.0" "1.57" "1.56.0" "1.56" "1.55.0" "1.55" + "1.54.0" "1.54" "1.53.0" "1.53" "1.52.0" "1.52" "1.51.0" "1.51" + "1.50.0" "1.50" "1.49.0" "1.49" "1.48.0" "1.48" "1.47.0" "1.47" "1.46.1" + "1.46.0" "1.46" "1.45.0" "1.45" "1.44.0" "1.44" "1.43.0" "1.43" "1.42.0" "1.42" + "1.41.0" "1.41" "1.40.0" "1.40" "1.39.0" "1.39" "1.38.0" "1.38" "1.37.0" "1.37" + "1.36.1" "1.36.0" "1.36" "1.35.1" "1.35.0" "1.35" "1.34.1" "1.34.0" + "1.34" "1.33.1" "1.33.0" "1.33") + + set(_boost_TEST_VERSIONS) + if(Boost_FIND_VERSION) + set(_Boost_FIND_VERSION_SHORT "${Boost_FIND_VERSION_MAJOR}.${Boost_FIND_VERSION_MINOR}") + # Select acceptable versions. + foreach(version ${_Boost_KNOWN_VERSIONS}) + if(NOT "${version}" VERSION_LESS "${Boost_FIND_VERSION}") + # This version is high enough. + list(APPEND _boost_TEST_VERSIONS "${version}") + elseif("${version}.99" VERSION_EQUAL "${_Boost_FIND_VERSION_SHORT}.99") + # This version is a short-form for the requested version with + # the patch level dropped. + list(APPEND _boost_TEST_VERSIONS "${version}") + endif() + endforeach() + else() + # Any version is acceptable. + set(_boost_TEST_VERSIONS "${_Boost_KNOWN_VERSIONS}") + endif() +endif() + +_Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "_boost_TEST_VERSIONS") +_Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "Boost_USE_MULTITHREADED") +_Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "Boost_USE_STATIC_LIBS") +_Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "Boost_USE_STATIC_RUNTIME") +_Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "Boost_ADDITIONAL_VERSIONS") +_Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "Boost_NO_SYSTEM_PATHS") + +cmake_policy(GET CMP0074 _Boost_CMP0074) +if(NOT "x${_Boost_CMP0074}x" STREQUAL "xNEWx") + _Boost_CHECK_SPELLING(Boost_ROOT) +endif() +unset(_Boost_CMP0074) +_Boost_CHECK_SPELLING(Boost_LIBRARYDIR) +_Boost_CHECK_SPELLING(Boost_INCLUDEDIR) + +# Collect environment variable inputs as hints. Do not consider changes. +foreach(v BOOSTROOT BOOST_ROOT BOOST_INCLUDEDIR BOOST_LIBRARYDIR) + set(_env $ENV{${v}}) + if(_env) + file(TO_CMAKE_PATH "${_env}" _ENV_${v}) + else() + set(_ENV_${v} "") + endif() +endforeach() +if(NOT _ENV_BOOST_ROOT AND _ENV_BOOSTROOT) + set(_ENV_BOOST_ROOT "${_ENV_BOOSTROOT}") +endif() + +# Collect inputs and cached results. Detect changes since the last run. +if(NOT BOOST_ROOT AND BOOSTROOT) + set(BOOST_ROOT "${BOOSTROOT}") +endif() +set(_Boost_VARS_DIR + BOOST_ROOT + Boost_NO_SYSTEM_PATHS + ) + +_Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "BOOST_ROOT") +_Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "BOOST_ROOT" ENVIRONMENT) +_Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "BOOST_INCLUDEDIR") +_Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "BOOST_INCLUDEDIR" ENVIRONMENT) +_Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "BOOST_LIBRARYDIR") +_Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "BOOST_LIBRARYDIR" ENVIRONMENT) + +# ------------------------------------------------------------------------ +# Search for Boost include DIR +# ------------------------------------------------------------------------ + +set(_Boost_VARS_INC BOOST_INCLUDEDIR Boost_INCLUDE_DIR Boost_ADDITIONAL_VERSIONS) +_Boost_CHANGE_DETECT(_Boost_CHANGE_INCDIR ${_Boost_VARS_DIR} ${_Boost_VARS_INC}) +# Clear Boost_INCLUDE_DIR if it did not change but other input affecting the +# location did. We will find a new one based on the new inputs. +if(_Boost_CHANGE_INCDIR AND NOT _Boost_INCLUDE_DIR_CHANGED) + unset(Boost_INCLUDE_DIR CACHE) +endif() + +if(NOT Boost_INCLUDE_DIR) + set(_boost_INCLUDE_SEARCH_DIRS "") + if(BOOST_INCLUDEDIR) + list(APPEND _boost_INCLUDE_SEARCH_DIRS ${BOOST_INCLUDEDIR}) + elseif(_ENV_BOOST_INCLUDEDIR) + list(APPEND _boost_INCLUDE_SEARCH_DIRS ${_ENV_BOOST_INCLUDEDIR}) + endif() + + if( BOOST_ROOT ) + list(APPEND _boost_INCLUDE_SEARCH_DIRS ${BOOST_ROOT}/include ${BOOST_ROOT}) + elseif( _ENV_BOOST_ROOT ) + list(APPEND _boost_INCLUDE_SEARCH_DIRS ${_ENV_BOOST_ROOT}/include ${_ENV_BOOST_ROOT}) + endif() + + if( Boost_NO_SYSTEM_PATHS) + list(APPEND _boost_INCLUDE_SEARCH_DIRS NO_CMAKE_SYSTEM_PATH NO_SYSTEM_ENVIRONMENT_PATH) + else() + if("x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xMSVC") + foreach(ver ${_boost_TEST_VERSIONS}) + string(REPLACE "." "_" ver "${ver}") + list(APPEND _boost_INCLUDE_SEARCH_DIRS PATHS "C:/local/boost_${ver}") + endforeach() + endif() + list(APPEND _boost_INCLUDE_SEARCH_DIRS PATHS + C:/boost/include + C:/boost + /sw/local/include + ) + endif() + + # Try to find Boost by stepping backwards through the Boost versions + # we know about. + # Build a list of path suffixes for each version. + set(_boost_PATH_SUFFIXES) + foreach(_boost_VER ${_boost_TEST_VERSIONS}) + # Add in a path suffix, based on the required version, ideally + # we could read this from version.hpp, but for that to work we'd + # need to know the include dir already + set(_boost_BOOSTIFIED_VERSION) + + # Transform 1.35 => 1_35 and 1.36.0 => 1_36_0 + if(_boost_VER MATCHES "([0-9]+)\\.([0-9]+)\\.([0-9]+)") + set(_boost_BOOSTIFIED_VERSION + "${CMAKE_MATCH_1}_${CMAKE_MATCH_2}_${CMAKE_MATCH_3}") + elseif(_boost_VER MATCHES "([0-9]+)\\.([0-9]+)") + set(_boost_BOOSTIFIED_VERSION + "${CMAKE_MATCH_1}_${CMAKE_MATCH_2}") + endif() + + list(APPEND _boost_PATH_SUFFIXES + "boost-${_boost_BOOSTIFIED_VERSION}" + "boost_${_boost_BOOSTIFIED_VERSION}" + "boost/boost-${_boost_BOOSTIFIED_VERSION}" + "boost/boost_${_boost_BOOSTIFIED_VERSION}" + ) + + endforeach() + + _Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "_boost_INCLUDE_SEARCH_DIRS") + _Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "_boost_PATH_SUFFIXES") + + # Look for a standard boost header file. + find_path(Boost_INCLUDE_DIR + NAMES boost/config.hpp + HINTS ${_boost_INCLUDE_SEARCH_DIRS} + PATH_SUFFIXES ${_boost_PATH_SUFFIXES} + ) +endif() + +# ------------------------------------------------------------------------ +# Extract version information from version.hpp +# ------------------------------------------------------------------------ + +if(Boost_INCLUDE_DIR) + _Boost_DEBUG_PRINT("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" + "location of version.hpp: ${Boost_INCLUDE_DIR}/boost/version.hpp") + + # Extract Boost_VERSION_MACRO and Boost_LIB_VERSION from version.hpp + set(Boost_VERSION_MACRO 0) + set(Boost_LIB_VERSION "") + file(STRINGS "${Boost_INCLUDE_DIR}/boost/version.hpp" _boost_VERSION_HPP_CONTENTS REGEX "#define BOOST_(LIB_)?VERSION ") + if("${_boost_VERSION_HPP_CONTENTS}" MATCHES "#define BOOST_VERSION ([0-9]+)") + set(Boost_VERSION_MACRO "${CMAKE_MATCH_1}") + endif() + if("${_boost_VERSION_HPP_CONTENTS}" MATCHES "#define BOOST_LIB_VERSION \"([0-9_]+)\"") + set(Boost_LIB_VERSION "${CMAKE_MATCH_1}") + endif() + unset(_boost_VERSION_HPP_CONTENTS) + + # Calculate version components + math(EXPR Boost_VERSION_MAJOR "${Boost_VERSION_MACRO} / 100000") + math(EXPR Boost_VERSION_MINOR "${Boost_VERSION_MACRO} / 100 % 1000") + math(EXPR Boost_VERSION_PATCH "${Boost_VERSION_MACRO} % 100") + set(Boost_VERSION_COUNT 3) + + # Define alias variables for backwards compat. + set(Boost_MAJOR_VERSION ${Boost_VERSION_MAJOR}) + set(Boost_MINOR_VERSION ${Boost_VERSION_MINOR}) + set(Boost_SUBMINOR_VERSION ${Boost_VERSION_PATCH}) + + # Define Boost version in x.y.z format + set(Boost_VERSION_STRING "${Boost_VERSION_MAJOR}.${Boost_VERSION_MINOR}.${Boost_VERSION_PATCH}") + + # Define final Boost_VERSION + cmake_policy(GET CMP0093 _Boost_CMP0093 + PARENT_SCOPE # undocumented, do not use outside of CMake + ) + if("x${_Boost_CMP0093}x" STREQUAL "xNEWx") + set(Boost_VERSION ${Boost_VERSION_STRING}) + else() + set(Boost_VERSION ${Boost_VERSION_MACRO}) + endif() + unset(_Boost_CMP0093) + + _Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "Boost_VERSION") + _Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "Boost_VERSION_STRING") + _Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "Boost_VERSION_MACRO") + _Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "Boost_VERSION_MAJOR") + _Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "Boost_VERSION_MINOR") + _Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "Boost_VERSION_PATCH") + _Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "Boost_VERSION_COUNT") +endif() + +# ------------------------------------------------------------------------ +# Prefix initialization +# ------------------------------------------------------------------------ + +if ( NOT DEFINED Boost_LIB_PREFIX ) + # Boost's static libraries use a "lib" prefix on DLL platforms + # to distinguish them from the DLL import libraries. + if (Boost_USE_STATIC_LIBS AND ( + (WIN32 AND NOT CYGWIN) + OR GHSMULTI + )) + set(Boost_LIB_PREFIX "lib") + else() + set(Boost_LIB_PREFIX "") + endif() +endif() + +if ( NOT Boost_NAMESPACE ) + set(Boost_NAMESPACE "boost") +endif() + +_Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "Boost_LIB_PREFIX") +_Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "Boost_NAMESPACE") + +# ------------------------------------------------------------------------ +# Suffix initialization and compiler suffix detection. +# ------------------------------------------------------------------------ + +set(_Boost_VARS_NAME + Boost_NAMESPACE + Boost_COMPILER + Boost_THREADAPI + Boost_USE_DEBUG_PYTHON + Boost_USE_MULTITHREADED + Boost_USE_STATIC_LIBS + Boost_USE_STATIC_RUNTIME + Boost_USE_STLPORT + Boost_USE_STLPORT_DEPRECATED_NATIVE_IOSTREAMS + ) +_Boost_CHANGE_DETECT(_Boost_CHANGE_LIBNAME ${_Boost_VARS_NAME}) + +# Setting some more suffixes for the library +if (Boost_COMPILER) + set(_boost_COMPILER ${Boost_COMPILER}) + _Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" + "_boost_COMPILER" SOURCE "user-specified via Boost_COMPILER") +else() + # Attempt to guess the compiler suffix + # NOTE: this is not perfect yet, if you experience any issues + # please report them and use the Boost_COMPILER variable + # to work around the problems. + _Boost_GUESS_COMPILER_PREFIX(_boost_COMPILER) +endif() + +set (_boost_MULTITHREADED "-mt") +if( NOT Boost_USE_MULTITHREADED ) + set (_boost_MULTITHREADED "") +endif() +_Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "_boost_MULTITHREADED") + +#====================== +# Systematically build up the Boost ABI tag for the 'tagged' and 'versioned' layouts +# http://boost.org/doc/libs/1_66_0/more/getting_started/windows.html#library-naming +# http://boost.org/doc/libs/1_66_0/boost/config/auto_link.hpp +# http://boost.org/doc/libs/1_66_0/tools/build/src/tools/common.jam +# http://boost.org/doc/libs/1_66_0/boostcpp.jam +set( _boost_RELEASE_ABI_TAG "-") +set( _boost_DEBUG_ABI_TAG "-") +# Key Use this library when: +# s linking statically to the C++ standard library and +# compiler runtime support libraries. +if(Boost_USE_STATIC_RUNTIME) + set( _boost_RELEASE_ABI_TAG "${_boost_RELEASE_ABI_TAG}s") + set( _boost_DEBUG_ABI_TAG "${_boost_DEBUG_ABI_TAG}s") +endif() +# g using debug versions of the standard and runtime +# support libraries +if(WIN32 AND Boost_USE_DEBUG_RUNTIME) + if("x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xMSVC" + OR "x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xClang" + OR "x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xIntel" + OR "x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xIntelLLVM") + string(APPEND _boost_DEBUG_ABI_TAG "g") + endif() +endif() +# y using special debug build of python +if(Boost_USE_DEBUG_PYTHON) + string(APPEND _boost_DEBUG_ABI_TAG "y") +endif() +# d using a debug version of your code +string(APPEND _boost_DEBUG_ABI_TAG "d") +# p using the STLport standard library rather than the +# default one supplied with your compiler +if(Boost_USE_STLPORT) + string(APPEND _boost_RELEASE_ABI_TAG "p") + string(APPEND _boost_DEBUG_ABI_TAG "p") +endif() +# n using the STLport deprecated "native iostreams" feature +# removed from the documentation in 1.43.0 but still present in +# boost/config/auto_link.hpp +if(Boost_USE_STLPORT_DEPRECATED_NATIVE_IOSTREAMS) + string(APPEND _boost_RELEASE_ABI_TAG "n") + string(APPEND _boost_DEBUG_ABI_TAG "n") +endif() + +# -x86 Architecture and address model tag +# First character is the architecture, then word-size, either 32 or 64 +# Only used in 'versioned' layout, added in Boost 1.66.0 +if(DEFINED Boost_ARCHITECTURE) + set(_boost_ARCHITECTURE_TAG "${Boost_ARCHITECTURE}") + _Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" + "_boost_ARCHITECTURE_TAG" SOURCE "user-specified via Boost_ARCHITECTURE") +else() + set(_boost_ARCHITECTURE_TAG "") + # {CMAKE_CXX_COMPILER_ARCHITECTURE_ID} is not currently set for all compilers + if(NOT "x${CMAKE_CXX_COMPILER_ARCHITECTURE_ID}" STREQUAL "x" AND NOT Boost_VERSION_STRING VERSION_LESS 1.66.0) + string(APPEND _boost_ARCHITECTURE_TAG "-") + # This needs to be kept in-sync with the section of CMakePlatformId.h.in + # inside 'defined(_WIN32) && defined(_MSC_VER)' + if(CMAKE_CXX_COMPILER_ARCHITECTURE_ID STREQUAL "IA64") + string(APPEND _boost_ARCHITECTURE_TAG "i") + elseif(CMAKE_CXX_COMPILER_ARCHITECTURE_ID STREQUAL "X86" + OR CMAKE_CXX_COMPILER_ARCHITECTURE_ID STREQUAL "x64") + string(APPEND _boost_ARCHITECTURE_TAG "x") + elseif(CMAKE_CXX_COMPILER_ARCHITECTURE_ID MATCHES "^ARM") + string(APPEND _boost_ARCHITECTURE_TAG "a") + elseif(CMAKE_CXX_COMPILER_ARCHITECTURE_ID STREQUAL "MIPS") + string(APPEND _boost_ARCHITECTURE_TAG "m") + endif() + + if(CMAKE_SIZEOF_VOID_P EQUAL 8) + string(APPEND _boost_ARCHITECTURE_TAG "64") + else() + string(APPEND _boost_ARCHITECTURE_TAG "32") + endif() + endif() + _Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" + "_boost_ARCHITECTURE_TAG" SOURCE "detected") +endif() + +_Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "_boost_RELEASE_ABI_TAG") +_Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "_boost_DEBUG_ABI_TAG") + +# ------------------------------------------------------------------------ +# Begin finding boost libraries +# ------------------------------------------------------------------------ + +set(_Boost_VARS_LIB "") +foreach(c DEBUG RELEASE) + set(_Boost_VARS_LIB_${c} BOOST_LIBRARYDIR Boost_LIBRARY_DIR_${c}) + list(APPEND _Boost_VARS_LIB ${_Boost_VARS_LIB_${c}}) + _Boost_CHANGE_DETECT(_Boost_CHANGE_LIBDIR_${c} ${_Boost_VARS_DIR} ${_Boost_VARS_LIB_${c}} Boost_INCLUDE_DIR) + # Clear Boost_LIBRARY_DIR_${c} if it did not change but other input affecting the + # location did. We will find a new one based on the new inputs. + if(_Boost_CHANGE_LIBDIR_${c} AND NOT _Boost_LIBRARY_DIR_${c}_CHANGED) + unset(Boost_LIBRARY_DIR_${c} CACHE) + endif() + + # If Boost_LIBRARY_DIR_[RELEASE,DEBUG] is set, prefer its value. + if(Boost_LIBRARY_DIR_${c}) + set(_boost_LIBRARY_SEARCH_DIRS_${c} ${Boost_LIBRARY_DIR_${c}} NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH) + else() + set(_boost_LIBRARY_SEARCH_DIRS_${c} "") + if(BOOST_LIBRARYDIR) + list(APPEND _boost_LIBRARY_SEARCH_DIRS_${c} ${BOOST_LIBRARYDIR}) + elseif(_ENV_BOOST_LIBRARYDIR) + list(APPEND _boost_LIBRARY_SEARCH_DIRS_${c} ${_ENV_BOOST_LIBRARYDIR}) + endif() + + if(BOOST_ROOT) + list(APPEND _boost_LIBRARY_SEARCH_DIRS_${c} ${BOOST_ROOT}/lib ${BOOST_ROOT}/stage/lib) + _Boost_UPDATE_WINDOWS_LIBRARY_SEARCH_DIRS_WITH_PREBUILT_PATHS(_boost_LIBRARY_SEARCH_DIRS_${c} "${BOOST_ROOT}") + elseif(_ENV_BOOST_ROOT) + list(APPEND _boost_LIBRARY_SEARCH_DIRS_${c} ${_ENV_BOOST_ROOT}/lib ${_ENV_BOOST_ROOT}/stage/lib) + _Boost_UPDATE_WINDOWS_LIBRARY_SEARCH_DIRS_WITH_PREBUILT_PATHS(_boost_LIBRARY_SEARCH_DIRS_${c} "${_ENV_BOOST_ROOT}") + endif() + + list(APPEND _boost_LIBRARY_SEARCH_DIRS_${c} + ${Boost_INCLUDE_DIR}/lib + ${Boost_INCLUDE_DIR}/../lib + ${Boost_INCLUDE_DIR}/stage/lib + ) + _Boost_UPDATE_WINDOWS_LIBRARY_SEARCH_DIRS_WITH_PREBUILT_PATHS(_boost_LIBRARY_SEARCH_DIRS_${c} "${Boost_INCLUDE_DIR}/..") + _Boost_UPDATE_WINDOWS_LIBRARY_SEARCH_DIRS_WITH_PREBUILT_PATHS(_boost_LIBRARY_SEARCH_DIRS_${c} "${Boost_INCLUDE_DIR}") + if( Boost_NO_SYSTEM_PATHS ) + list(APPEND _boost_LIBRARY_SEARCH_DIRS_${c} NO_CMAKE_SYSTEM_PATH NO_SYSTEM_ENVIRONMENT_PATH) + else() + foreach(ver ${_boost_TEST_VERSIONS}) + string(REPLACE "." "_" ver "${ver}") + _Boost_UPDATE_WINDOWS_LIBRARY_SEARCH_DIRS_WITH_PREBUILT_PATHS(_boost_LIBRARY_SEARCH_DIRS_${c} "C:/local/boost_${ver}") + endforeach() + _Boost_UPDATE_WINDOWS_LIBRARY_SEARCH_DIRS_WITH_PREBUILT_PATHS(_boost_LIBRARY_SEARCH_DIRS_${c} "C:/boost") + list(APPEND _boost_LIBRARY_SEARCH_DIRS_${c} PATHS + C:/boost/lib + C:/boost + /sw/local/lib + ) + endif() + endif() +endforeach() + +_Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "_boost_LIBRARY_SEARCH_DIRS_RELEASE") +_Boost_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "_boost_LIBRARY_SEARCH_DIRS_DEBUG") + +# Support preference of static libs by adjusting CMAKE_FIND_LIBRARY_SUFFIXES +if( Boost_USE_STATIC_LIBS ) + set( _boost_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES}) + if(WIN32) + list(INSERT CMAKE_FIND_LIBRARY_SUFFIXES 0 .lib .a) + else() + set(CMAKE_FIND_LIBRARY_SUFFIXES .a) + endif() +endif() + +# We want to use the tag inline below without risking double dashes +if(_boost_RELEASE_ABI_TAG) + if(${_boost_RELEASE_ABI_TAG} STREQUAL "-") + set(_boost_RELEASE_ABI_TAG "") + endif() +endif() +if(_boost_DEBUG_ABI_TAG) + if(${_boost_DEBUG_ABI_TAG} STREQUAL "-") + set(_boost_DEBUG_ABI_TAG "") + endif() +endif() + +# The previous behavior of FindBoost when Boost_USE_STATIC_LIBS was enabled +# on WIN32 was to: +# 1. Search for static libs compiled against a SHARED C++ standard runtime library (use if found) +# 2. Search for static libs compiled against a STATIC C++ standard runtime library (use if found) +# We maintain this behavior since changing it could break people's builds. +# To disable the ambiguous behavior, the user need only +# set Boost_USE_STATIC_RUNTIME either ON or OFF. +set(_boost_STATIC_RUNTIME_WORKAROUND false) +if(WIN32 AND Boost_USE_STATIC_LIBS) + if(NOT DEFINED Boost_USE_STATIC_RUNTIME) + set(_boost_STATIC_RUNTIME_WORKAROUND TRUE) + endif() +endif() + +# On versions < 1.35, remove the System library from the considered list +# since it wasn't added until 1.35. +if(Boost_VERSION_STRING AND Boost_FIND_COMPONENTS) + if(Boost_VERSION_STRING VERSION_LESS 1.35.0) + list(REMOVE_ITEM Boost_FIND_COMPONENTS system) + endif() +endif() + +# Additional components may be required via component dependencies. +# Add any missing components to the list. +_Boost_MISSING_DEPENDENCIES(Boost_FIND_COMPONENTS _Boost_EXTRA_FIND_COMPONENTS) + +# If thread is required, get the thread libs as a dependency +if("thread" IN_LIST Boost_FIND_COMPONENTS) + if(Boost_FIND_QUIETLY) + set(_Boost_find_quiet QUIET) + else() + set(_Boost_find_quiet "") + endif() + find_package(Threads ${_Boost_find_quiet}) + unset(_Boost_find_quiet) +endif() + +# If the user changed any of our control inputs flush previous results. +if(_Boost_CHANGE_LIBDIR_DEBUG OR _Boost_CHANGE_LIBDIR_RELEASE OR _Boost_CHANGE_LIBNAME) + foreach(COMPONENT ${_Boost_COMPONENTS_SEARCHED}) + string(TOUPPER ${COMPONENT} UPPERCOMPONENT) + foreach(c DEBUG RELEASE) + set(_var Boost_${UPPERCOMPONENT}_LIBRARY_${c}) + unset(${_var} CACHE) + set(${_var} "${_var}-NOTFOUND") + endforeach() + endforeach() + set(_Boost_COMPONENTS_SEARCHED "") +endif() + +foreach(COMPONENT ${Boost_FIND_COMPONENTS}) + string(TOUPPER ${COMPONENT} UPPERCOMPONENT) + + set( _boost_docstring_release "Boost ${COMPONENT} library (release)") + set( _boost_docstring_debug "Boost ${COMPONENT} library (debug)") + + # Compute component-specific hints. + set(_Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT "") + if(${COMPONENT} STREQUAL "mpi" OR ${COMPONENT} STREQUAL "mpi_python" OR + ${COMPONENT} STREQUAL "graph_parallel") + foreach(lib ${MPI_CXX_LIBRARIES} ${MPI_C_LIBRARIES}) + if(IS_ABSOLUTE "${lib}") + get_filename_component(libdir "${lib}" PATH) + string(REPLACE "\\" "/" libdir "${libdir}") + list(APPEND _Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT ${libdir}) + endif() + endforeach() + endif() + + # Handle Python version suffixes + unset(COMPONENT_PYTHON_VERSION_MAJOR) + unset(COMPONENT_PYTHON_VERSION_MINOR) + if(${COMPONENT} MATCHES "^(python|mpi_python|numpy)([0-9])\$") + set(COMPONENT_UNVERSIONED "${CMAKE_MATCH_1}") + set(COMPONENT_PYTHON_VERSION_MAJOR "${CMAKE_MATCH_2}") + elseif(${COMPONENT} MATCHES "^(python|mpi_python|numpy)([0-9])\\.?([0-9]+)\$") + set(COMPONENT_UNVERSIONED "${CMAKE_MATCH_1}") + set(COMPONENT_PYTHON_VERSION_MAJOR "${CMAKE_MATCH_2}") + set(COMPONENT_PYTHON_VERSION_MINOR "${CMAKE_MATCH_3}") + endif() + + unset(_Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT_NAME) + if (COMPONENT_PYTHON_VERSION_MINOR) + # Boost >= 1.67 + list(APPEND _Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT_NAME "${COMPONENT_UNVERSIONED}${COMPONENT_PYTHON_VERSION_MAJOR}${COMPONENT_PYTHON_VERSION_MINOR}") + # Debian/Ubuntu (Some versions omit the 2 and/or 3 from the suffix) + list(APPEND _Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT_NAME "${COMPONENT_UNVERSIONED}${COMPONENT_PYTHON_VERSION_MAJOR}-py${COMPONENT_PYTHON_VERSION_MAJOR}${COMPONENT_PYTHON_VERSION_MINOR}") + list(APPEND _Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT_NAME "${COMPONENT_UNVERSIONED}-py${COMPONENT_PYTHON_VERSION_MAJOR}${COMPONENT_PYTHON_VERSION_MINOR}") + # Gentoo + list(APPEND _Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT_NAME "${COMPONENT_UNVERSIONED}-${COMPONENT_PYTHON_VERSION_MAJOR}.${COMPONENT_PYTHON_VERSION_MINOR}") + # RPMs + list(APPEND _Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT_NAME "${COMPONENT_UNVERSIONED}-${COMPONENT_PYTHON_VERSION_MAJOR}${COMPONENT_PYTHON_VERSION_MINOR}") + endif() + if (COMPONENT_PYTHON_VERSION_MAJOR AND NOT COMPONENT_PYTHON_VERSION_MINOR) + # Boost < 1.67 + list(APPEND _Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT_NAME "${COMPONENT_UNVERSIONED}${COMPONENT_PYTHON_VERSION_MAJOR}") + endif() + + # Consolidate and report component-specific hints. + if(_Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT_NAME) + list(REMOVE_DUPLICATES _Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT_NAME) + _Boost_DEBUG_PRINT("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" + "Component-specific library search names for ${COMPONENT_NAME}: ${_Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT_NAME}") + endif() + if(_Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT) + list(REMOVE_DUPLICATES _Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT) + _Boost_DEBUG_PRINT("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" + "Component-specific library search paths for ${COMPONENT}: ${_Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT}") + endif() + + # + # Find headers + # + _Boost_COMPONENT_HEADERS("${COMPONENT}" Boost_${UPPERCOMPONENT}_HEADER_NAME) + # Look for a standard boost header file. + if(Boost_${UPPERCOMPONENT}_HEADER_NAME) + if(EXISTS "${Boost_INCLUDE_DIR}/${Boost_${UPPERCOMPONENT}_HEADER_NAME}") + set(Boost_${UPPERCOMPONENT}_HEADER ON) + else() + set(Boost_${UPPERCOMPONENT}_HEADER OFF) + endif() + else() + set(Boost_${UPPERCOMPONENT}_HEADER ON) + message(WARNING "No header defined for ${COMPONENT}; skipping header check " + "(note: header-only libraries have no designated component)") + endif() + + # + # Find RELEASE libraries + # + unset(_boost_RELEASE_NAMES) + foreach(component IN LISTS _Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT_NAME COMPONENT) + foreach(compiler IN LISTS _boost_COMPILER) + list(APPEND _boost_RELEASE_NAMES + ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component}${compiler}${_boost_MULTITHREADED}${_boost_RELEASE_ABI_TAG}${_boost_ARCHITECTURE_TAG}-${Boost_LIB_VERSION} + ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component}${compiler}${_boost_MULTITHREADED}${_boost_RELEASE_ABI_TAG}${_boost_ARCHITECTURE_TAG} + ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component}${compiler}${_boost_MULTITHREADED}${_boost_RELEASE_ABI_TAG} ) + endforeach() + list(APPEND _boost_RELEASE_NAMES + ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component}${_boost_MULTITHREADED}${_boost_RELEASE_ABI_TAG}${_boost_ARCHITECTURE_TAG}-${Boost_LIB_VERSION} + ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component}${_boost_MULTITHREADED}${_boost_RELEASE_ABI_TAG}${_boost_ARCHITECTURE_TAG} + ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component}${_boost_MULTITHREADED}${_boost_RELEASE_ABI_TAG} + ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component}${_boost_MULTITHREADED} + ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component} ) + if(_boost_STATIC_RUNTIME_WORKAROUND) + set(_boost_RELEASE_STATIC_ABI_TAG "-s${_boost_RELEASE_ABI_TAG}") + foreach(compiler IN LISTS _boost_COMPILER) + list(APPEND _boost_RELEASE_NAMES + ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component}${compiler}${_boost_MULTITHREADED}${_boost_RELEASE_STATIC_ABI_TAG}${_boost_ARCHITECTURE_TAG}-${Boost_LIB_VERSION} + ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component}${compiler}${_boost_MULTITHREADED}${_boost_RELEASE_STATIC_ABI_TAG}${_boost_ARCHITECTURE_TAG} + ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component}${compiler}${_boost_MULTITHREADED}${_boost_RELEASE_STATIC_ABI_TAG} ) + endforeach() + list(APPEND _boost_RELEASE_NAMES + ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component}${_boost_MULTITHREADED}${_boost_RELEASE_STATIC_ABI_TAG}${_boost_ARCHITECTURE_TAG}-${Boost_LIB_VERSION} + ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component}${_boost_MULTITHREADED}${_boost_RELEASE_STATIC_ABI_TAG}${_boost_ARCHITECTURE_TAG} + ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component}${_boost_MULTITHREADED}${_boost_RELEASE_STATIC_ABI_TAG} ) + endif() + endforeach() + if(Boost_THREADAPI AND ${COMPONENT} STREQUAL "thread") + _Boost_PREPEND_LIST_WITH_THREADAPI(_boost_RELEASE_NAMES ${_boost_RELEASE_NAMES}) + endif() + _Boost_DEBUG_PRINT("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" + "Searching for ${UPPERCOMPONENT}_LIBRARY_RELEASE: ${_boost_RELEASE_NAMES}") + + # if Boost_LIBRARY_DIR_RELEASE is not defined, + # but Boost_LIBRARY_DIR_DEBUG is, look there first for RELEASE libs + if(NOT Boost_LIBRARY_DIR_RELEASE AND Boost_LIBRARY_DIR_DEBUG) + list(INSERT _boost_LIBRARY_SEARCH_DIRS_RELEASE 0 ${Boost_LIBRARY_DIR_DEBUG}) + endif() + + # Avoid passing backslashes to _Boost_FIND_LIBRARY due to macro re-parsing. + string(REPLACE "\\" "/" _boost_LIBRARY_SEARCH_DIRS_tmp "${_boost_LIBRARY_SEARCH_DIRS_RELEASE}") + + if(Boost_USE_RELEASE_LIBS) + _Boost_FIND_LIBRARY(Boost_${UPPERCOMPONENT}_LIBRARY_RELEASE RELEASE + NAMES ${_boost_RELEASE_NAMES} + HINTS ${_boost_LIBRARY_SEARCH_DIRS_tmp} + NAMES_PER_DIR + DOC "${_boost_docstring_release}" + ) + endif() + + # + # Find DEBUG libraries + # + unset(_boost_DEBUG_NAMES) + foreach(component IN LISTS _Boost_FIND_LIBRARY_HINTS_FOR_COMPONENT_NAME COMPONENT) + foreach(compiler IN LISTS _boost_COMPILER) + list(APPEND _boost_DEBUG_NAMES + ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component}${compiler}${_boost_MULTITHREADED}${_boost_DEBUG_ABI_TAG}${_boost_ARCHITECTURE_TAG}-${Boost_LIB_VERSION} + ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component}${compiler}${_boost_MULTITHREADED}${_boost_DEBUG_ABI_TAG}${_boost_ARCHITECTURE_TAG} + ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component}${compiler}${_boost_MULTITHREADED}${_boost_DEBUG_ABI_TAG} ) + endforeach() + list(APPEND _boost_DEBUG_NAMES + ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component}${_boost_MULTITHREADED}${_boost_DEBUG_ABI_TAG}${_boost_ARCHITECTURE_TAG}-${Boost_LIB_VERSION} + ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component}${_boost_MULTITHREADED}${_boost_DEBUG_ABI_TAG}${_boost_ARCHITECTURE_TAG} + ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component}${_boost_MULTITHREADED}${_boost_DEBUG_ABI_TAG} + ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component}${_boost_MULTITHREADED} + ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component} ) + if(_boost_STATIC_RUNTIME_WORKAROUND) + set(_boost_DEBUG_STATIC_ABI_TAG "-s${_boost_DEBUG_ABI_TAG}") + foreach(compiler IN LISTS _boost_COMPILER) + list(APPEND _boost_DEBUG_NAMES + ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component}${compiler}${_boost_MULTITHREADED}${_boost_DEBUG_STATIC_ABI_TAG}${_boost_ARCHITECTURE_TAG}-${Boost_LIB_VERSION} + ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component}${compiler}${_boost_MULTITHREADED}${_boost_DEBUG_STATIC_ABI_TAG}${_boost_ARCHITECTURE_TAG} + ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component}${compiler}${_boost_MULTITHREADED}${_boost_DEBUG_STATIC_ABI_TAG} ) + endforeach() + list(APPEND _boost_DEBUG_NAMES + ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component}${_boost_MULTITHREADED}${_boost_DEBUG_STATIC_ABI_TAG}${_boost_ARCHITECTURE_TAG}-${Boost_LIB_VERSION} + ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component}${_boost_MULTITHREADED}${_boost_DEBUG_STATIC_ABI_TAG}${_boost_ARCHITECTURE_TAG} + ${Boost_LIB_PREFIX}${Boost_NAMESPACE}_${component}${_boost_MULTITHREADED}${_boost_DEBUG_STATIC_ABI_TAG} ) + endif() + endforeach() + if(Boost_THREADAPI AND ${COMPONENT} STREQUAL "thread") + _Boost_PREPEND_LIST_WITH_THREADAPI(_boost_DEBUG_NAMES ${_boost_DEBUG_NAMES}) + endif() + _Boost_DEBUG_PRINT("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" + "Searching for ${UPPERCOMPONENT}_LIBRARY_DEBUG: ${_boost_DEBUG_NAMES}") + + # if Boost_LIBRARY_DIR_DEBUG is not defined, + # but Boost_LIBRARY_DIR_RELEASE is, look there first for DEBUG libs + if(NOT Boost_LIBRARY_DIR_DEBUG AND Boost_LIBRARY_DIR_RELEASE) + list(INSERT _boost_LIBRARY_SEARCH_DIRS_DEBUG 0 ${Boost_LIBRARY_DIR_RELEASE}) + endif() + + # Avoid passing backslashes to _Boost_FIND_LIBRARY due to macro re-parsing. + string(REPLACE "\\" "/" _boost_LIBRARY_SEARCH_DIRS_tmp "${_boost_LIBRARY_SEARCH_DIRS_DEBUG}") + + if(Boost_USE_DEBUG_LIBS) + _Boost_FIND_LIBRARY(Boost_${UPPERCOMPONENT}_LIBRARY_DEBUG DEBUG + NAMES ${_boost_DEBUG_NAMES} + HINTS ${_boost_LIBRARY_SEARCH_DIRS_tmp} + NAMES_PER_DIR + DOC "${_boost_docstring_debug}" + ) + endif () + + if(Boost_REALPATH) + _Boost_SWAP_WITH_REALPATH(Boost_${UPPERCOMPONENT}_LIBRARY_RELEASE "${_boost_docstring_release}") + _Boost_SWAP_WITH_REALPATH(Boost_${UPPERCOMPONENT}_LIBRARY_DEBUG "${_boost_docstring_debug}" ) + endif() + + _Boost_ADJUST_LIB_VARS(${UPPERCOMPONENT}) + + # Check if component requires some compiler features + _Boost_COMPILER_FEATURES(${COMPONENT} _Boost_${UPPERCOMPONENT}_COMPILER_FEATURES) + +endforeach() + +# Restore the original find library ordering +if( Boost_USE_STATIC_LIBS ) + set(CMAKE_FIND_LIBRARY_SUFFIXES ${_boost_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES}) +endif() + +# ------------------------------------------------------------------------ +# End finding boost libraries +# ------------------------------------------------------------------------ + +set(Boost_INCLUDE_DIRS ${Boost_INCLUDE_DIR}) +set(Boost_LIBRARY_DIRS) +if(Boost_LIBRARY_DIR_RELEASE) + list(APPEND Boost_LIBRARY_DIRS ${Boost_LIBRARY_DIR_RELEASE}) +endif() +if(Boost_LIBRARY_DIR_DEBUG) + list(APPEND Boost_LIBRARY_DIRS ${Boost_LIBRARY_DIR_DEBUG}) +endif() +if(Boost_LIBRARY_DIRS) + list(REMOVE_DUPLICATES Boost_LIBRARY_DIRS) +endif() + +# ------------------------------------------------------------------------ +# Call FPHSA helper, see https://cmake.org/cmake/help/latest/module/FindPackageHandleStandardArgs.html +# ------------------------------------------------------------------------ + +# Define aliases as needed by the component handler in the FPHSA helper below +foreach(_comp IN LISTS Boost_FIND_COMPONENTS) + string(TOUPPER ${_comp} _uppercomp) + if(DEFINED Boost_${_uppercomp}_FOUND) + set(Boost_${_comp}_FOUND ${Boost_${_uppercomp}_FOUND}) + endif() +endforeach() + +find_package_handle_standard_args(Boost + REQUIRED_VARS Boost_INCLUDE_DIR + VERSION_VAR Boost_VERSION_STRING + HANDLE_COMPONENTS) + +if(Boost_FOUND) + if( NOT Boost_LIBRARY_DIRS ) + # Compatibility Code for backwards compatibility with CMake + # 2.4's FindBoost module. + + # Look for the boost library path. + # Note that the user may not have installed any libraries + # so it is quite possible the Boost_LIBRARY_DIRS may not exist. + set(_boost_LIB_DIR ${Boost_INCLUDE_DIR}) + + if("${_boost_LIB_DIR}" MATCHES "boost-[0-9]+") + get_filename_component(_boost_LIB_DIR ${_boost_LIB_DIR} PATH) + endif() + + if("${_boost_LIB_DIR}" MATCHES "/include$") + # Strip off the trailing "/include" in the path. + get_filename_component(_boost_LIB_DIR ${_boost_LIB_DIR} PATH) + endif() + + if(EXISTS "${_boost_LIB_DIR}/lib") + string(APPEND _boost_LIB_DIR /lib) + elseif(EXISTS "${_boost_LIB_DIR}/stage/lib") + string(APPEND _boost_LIB_DIR "/stage/lib") + else() + set(_boost_LIB_DIR "") + endif() + + if(_boost_LIB_DIR AND EXISTS "${_boost_LIB_DIR}") + set(Boost_LIBRARY_DIRS ${_boost_LIB_DIR}) + endif() + + endif() +else() + # Boost headers were not found so no components were found. + foreach(COMPONENT ${Boost_FIND_COMPONENTS}) + string(TOUPPER ${COMPONENT} UPPERCOMPONENT) + set(Boost_${UPPERCOMPONENT}_FOUND 0) + endforeach() +endif() + +# ------------------------------------------------------------------------ +# Add imported targets +# ------------------------------------------------------------------------ + +if(Boost_FOUND) + # The builtin CMake package in Boost 1.70+ introduces a new name + # for the header-only lib, let's provide the same UI in module mode + if(NOT TARGET Boost::headers) + add_library(Boost::headers INTERFACE IMPORTED) + if(Boost_INCLUDE_DIRS) + set_target_properties(Boost::headers PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${Boost_INCLUDE_DIRS}") + endif() + endif() + + # Define the old target name for header-only libraries for backwards + # compat. + if(NOT TARGET Boost::boost) + add_library(Boost::boost INTERFACE IMPORTED) + set_target_properties(Boost::boost + PROPERTIES INTERFACE_LINK_LIBRARIES Boost::headers) + endif() + + foreach(COMPONENT ${Boost_FIND_COMPONENTS}) + if(_Boost_IMPORTED_TARGETS AND NOT TARGET Boost::${COMPONENT}) + string(TOUPPER ${COMPONENT} UPPERCOMPONENT) + if(Boost_${UPPERCOMPONENT}_FOUND) + if(Boost_USE_STATIC_LIBS) + add_library(Boost::${COMPONENT} STATIC IMPORTED) + else() + # Even if Boost_USE_STATIC_LIBS is OFF, we might have static + # libraries as a result. + add_library(Boost::${COMPONENT} UNKNOWN IMPORTED) + endif() + if(Boost_INCLUDE_DIRS) + set_target_properties(Boost::${COMPONENT} PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${Boost_INCLUDE_DIRS}") + endif() + if(EXISTS "${Boost_${UPPERCOMPONENT}_LIBRARY}") + set_target_properties(Boost::${COMPONENT} PROPERTIES + IMPORTED_LINK_INTERFACE_LANGUAGES "CXX" + IMPORTED_LOCATION "${Boost_${UPPERCOMPONENT}_LIBRARY}") + endif() + if(EXISTS "${Boost_${UPPERCOMPONENT}_LIBRARY_RELEASE}") + set_property(TARGET Boost::${COMPONENT} APPEND PROPERTY + IMPORTED_CONFIGURATIONS RELEASE) + set_target_properties(Boost::${COMPONENT} PROPERTIES + IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "CXX" + IMPORTED_LOCATION_RELEASE "${Boost_${UPPERCOMPONENT}_LIBRARY_RELEASE}") + endif() + if(EXISTS "${Boost_${UPPERCOMPONENT}_LIBRARY_DEBUG}") + set_property(TARGET Boost::${COMPONENT} APPEND PROPERTY + IMPORTED_CONFIGURATIONS DEBUG) + set_target_properties(Boost::${COMPONENT} PROPERTIES + IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "CXX" + IMPORTED_LOCATION_DEBUG "${Boost_${UPPERCOMPONENT}_LIBRARY_DEBUG}") + endif() + if(_Boost_${UPPERCOMPONENT}_DEPENDENCIES) + unset(_Boost_${UPPERCOMPONENT}_TARGET_DEPENDENCIES) + foreach(dep ${_Boost_${UPPERCOMPONENT}_DEPENDENCIES}) + list(APPEND _Boost_${UPPERCOMPONENT}_TARGET_DEPENDENCIES Boost::${dep}) + endforeach() + if(COMPONENT STREQUAL "thread") + list(APPEND _Boost_${UPPERCOMPONENT}_TARGET_DEPENDENCIES Threads::Threads) + endif() + set_target_properties(Boost::${COMPONENT} PROPERTIES + INTERFACE_LINK_LIBRARIES "${_Boost_${UPPERCOMPONENT}_TARGET_DEPENDENCIES}") + endif() + if(_Boost_${UPPERCOMPONENT}_COMPILER_FEATURES) + set_target_properties(Boost::${COMPONENT} PROPERTIES + INTERFACE_COMPILE_FEATURES "${_Boost_${UPPERCOMPONENT}_COMPILER_FEATURES}") + endif() + endif() + endif() + endforeach() + + # Supply Boost_LIB_DIAGNOSTIC_DEFINITIONS as a convenience target. It + # will only contain any interface definitions on WIN32, but is created + # on all platforms to keep end user code free from platform dependent + # code. Also provide convenience targets to disable autolinking and + # enable dynamic linking. + if(NOT TARGET Boost::diagnostic_definitions) + add_library(Boost::diagnostic_definitions INTERFACE IMPORTED) + add_library(Boost::disable_autolinking INTERFACE IMPORTED) + add_library(Boost::dynamic_linking INTERFACE IMPORTED) + set_target_properties(Boost::dynamic_linking PROPERTIES + INTERFACE_COMPILE_DEFINITIONS "BOOST_ALL_DYN_LINK") + endif() + if(WIN32) + # In windows, automatic linking is performed, so you do not have + # to specify the libraries. If you are linking to a dynamic + # runtime, then you can choose to link to either a static or a + # dynamic Boost library, the default is to do a static link. You + # can alter this for a specific library "whatever" by defining + # BOOST_WHATEVER_DYN_LINK to force Boost library "whatever" to be + # linked dynamically. Alternatively you can force all Boost + # libraries to dynamic link by defining BOOST_ALL_DYN_LINK. + + # This feature can be disabled for Boost library "whatever" by + # defining BOOST_WHATEVER_NO_LIB, or for all of Boost by defining + # BOOST_ALL_NO_LIB. + + # If you want to observe which libraries are being linked against + # then defining BOOST_LIB_DIAGNOSTIC will cause the auto-linking + # code to emit a #pragma message each time a library is selected + # for linking. + set(Boost_LIB_DIAGNOSTIC_DEFINITIONS "-DBOOST_LIB_DIAGNOSTIC") + set_target_properties(Boost::diagnostic_definitions PROPERTIES + INTERFACE_COMPILE_DEFINITIONS "BOOST_LIB_DIAGNOSTIC") + set_target_properties(Boost::disable_autolinking PROPERTIES + INTERFACE_COMPILE_DEFINITIONS "BOOST_ALL_NO_LIB") + endif() +endif() + +# ------------------------------------------------------------------------ +# Finalize +# ------------------------------------------------------------------------ + +# Report Boost_LIBRARIES +set(Boost_LIBRARIES "") +foreach(_comp IN LISTS Boost_FIND_COMPONENTS) + string(TOUPPER ${_comp} _uppercomp) + if(Boost_${_uppercomp}_FOUND) + list(APPEND Boost_LIBRARIES ${Boost_${_uppercomp}_LIBRARY}) + if(_comp STREQUAL "thread") + list(APPEND Boost_LIBRARIES ${CMAKE_THREAD_LIBS_INIT}) + endif() + endif() +endforeach() + +# Configure display of cache entries in GUI. +foreach(v BOOSTROOT BOOST_ROOT ${_Boost_VARS_INC} ${_Boost_VARS_LIB}) + get_property(_type CACHE ${v} PROPERTY TYPE) + if(_type) + set_property(CACHE ${v} PROPERTY ADVANCED 1) + if("x${_type}" STREQUAL "xUNINITIALIZED") + if("x${v}" STREQUAL "xBoost_ADDITIONAL_VERSIONS") + set_property(CACHE ${v} PROPERTY TYPE STRING) + else() + set_property(CACHE ${v} PROPERTY TYPE PATH) + endif() + endif() + endif() +endforeach() + +# Record last used values of input variables so we can +# detect on the next run if the user changed them. +foreach(v + ${_Boost_VARS_INC} ${_Boost_VARS_LIB} + ${_Boost_VARS_DIR} ${_Boost_VARS_NAME} + ) + if(DEFINED ${v}) + set(_${v}_LAST "${${v}}" CACHE INTERNAL "Last used ${v} value.") + else() + unset(_${v}_LAST CACHE) + endif() +endforeach() + +# Maintain a persistent list of components requested anywhere since +# the last flush. +set(_Boost_COMPONENTS_SEARCHED "${_Boost_COMPONENTS_SEARCHED}") +list(APPEND _Boost_COMPONENTS_SEARCHED ${Boost_FIND_COMPONENTS}) +list(REMOVE_DUPLICATES _Boost_COMPONENTS_SEARCHED) +list(SORT _Boost_COMPONENTS_SEARCHED) +set(_Boost_COMPONENTS_SEARCHED "${_Boost_COMPONENTS_SEARCHED}" + CACHE INTERNAL "Components requested for this build tree.") + +# Restore project's policies +cmake_policy(POP) diff --git a/cmake/modules/FindEigen3.cmake b/cmake/modules/FindEigen3.cmake new file mode 100644 index 0000000..657440b --- /dev/null +++ b/cmake/modules/FindEigen3.cmake @@ -0,0 +1,106 @@ +# - Try to find Eigen3 lib +# +# This module supports requiring a minimum version, e.g. you can do +# find_package(Eigen3 3.1.2) +# to require version 3.1.2 or newer of Eigen3. +# +# Once done this will define +# +# EIGEN3_FOUND - system has eigen lib with correct version +# EIGEN3_INCLUDE_DIR - the eigen include directory +# EIGEN3_VERSION - eigen version +# +# and the following imported target: +# +# Eigen3::Eigen - The header-only Eigen library +# +# This module reads hints about search locations from +# the following enviroment variables: +# +# EIGEN3_ROOT +# EIGEN3_ROOT_DIR + +# Copyright (c) 2006, 2007 Montel Laurent, +# Copyright (c) 2008, 2009 Gael Guennebaud, +# Copyright (c) 2009 Benoit Jacob +# Redistribution and use is allowed according to the terms of the 2-clause BSD license. + +if(NOT Eigen3_FIND_VERSION) + if(NOT Eigen3_FIND_VERSION_MAJOR) + set(Eigen3_FIND_VERSION_MAJOR 2) + endif(NOT Eigen3_FIND_VERSION_MAJOR) + if(NOT Eigen3_FIND_VERSION_MINOR) + set(Eigen3_FIND_VERSION_MINOR 91) + endif(NOT Eigen3_FIND_VERSION_MINOR) + if(NOT Eigen3_FIND_VERSION_PATCH) + set(Eigen3_FIND_VERSION_PATCH 0) + endif(NOT Eigen3_FIND_VERSION_PATCH) + + set(Eigen3_FIND_VERSION "${Eigen3_FIND_VERSION_MAJOR}.${Eigen3_FIND_VERSION_MINOR}.${Eigen3_FIND_VERSION_PATCH}") +endif(NOT Eigen3_FIND_VERSION) + +macro(_eigen3_check_version) + file(READ "${EIGEN3_INCLUDE_DIR}/Eigen/src/Core/util/Macros.h" _eigen3_version_header) + + string(REGEX MATCH "define[ \t]+EIGEN_WORLD_VERSION[ \t]+([0-9]+)" _eigen3_world_version_match "${_eigen3_version_header}") + set(EIGEN3_WORLD_VERSION "${CMAKE_MATCH_1}") + string(REGEX MATCH "define[ \t]+EIGEN_MAJOR_VERSION[ \t]+([0-9]+)" _eigen3_major_version_match "${_eigen3_version_header}") + set(EIGEN3_MAJOR_VERSION "${CMAKE_MATCH_1}") + string(REGEX MATCH "define[ \t]+EIGEN_MINOR_VERSION[ \t]+([0-9]+)" _eigen3_minor_version_match "${_eigen3_version_header}") + set(EIGEN3_MINOR_VERSION "${CMAKE_MATCH_1}") + + set(EIGEN3_VERSION ${EIGEN3_WORLD_VERSION}.${EIGEN3_MAJOR_VERSION}.${EIGEN3_MINOR_VERSION}) + if(${EIGEN3_VERSION} VERSION_LESS ${Eigen3_FIND_VERSION}) + set(EIGEN3_VERSION_OK FALSE) + else(${EIGEN3_VERSION} VERSION_LESS ${Eigen3_FIND_VERSION}) + set(EIGEN3_VERSION_OK TRUE) + endif(${EIGEN3_VERSION} VERSION_LESS ${Eigen3_FIND_VERSION}) + + if(NOT EIGEN3_VERSION_OK) + + message(STATUS "Eigen3 version ${EIGEN3_VERSION} found in ${EIGEN3_INCLUDE_DIR}, " + "but at least version ${Eigen3_FIND_VERSION} is required") + endif(NOT EIGEN3_VERSION_OK) +endmacro(_eigen3_check_version) + +if (EIGEN3_INCLUDE_DIR) + + # in cache already + _eigen3_check_version() + set(EIGEN3_FOUND ${EIGEN3_VERSION_OK}) + +else (EIGEN3_INCLUDE_DIR) + + # search first if an Eigen3Config.cmake is available in the system, + # if successful this would set EIGEN3_INCLUDE_DIR and the rest of + # the script will work as usual + find_package(Eigen3 ${Eigen3_FIND_VERSION} NO_MODULE QUIET) + + if(NOT EIGEN3_INCLUDE_DIR) + find_path(EIGEN3_INCLUDE_DIR NAMES signature_of_eigen3_matrix_library + HINTS + ENV EIGEN3_ROOT + ENV EIGEN3_ROOT_DIR + PATHS + ${CMAKE_INSTALL_PREFIX}/include + ${KDE4_INCLUDE_DIR} + PATH_SUFFIXES eigen3 eigen + ) + endif(NOT EIGEN3_INCLUDE_DIR) + + if(EIGEN3_INCLUDE_DIR) + _eigen3_check_version() + endif(EIGEN3_INCLUDE_DIR) + + include(FindPackageHandleStandardArgs) + find_package_handle_standard_args(Eigen3 DEFAULT_MSG EIGEN3_INCLUDE_DIR EIGEN3_VERSION_OK) + + mark_as_advanced(EIGEN3_INCLUDE_DIR) + +endif(EIGEN3_INCLUDE_DIR) + +if(EIGEN3_FOUND AND NOT TARGET Eigen3::Eigen) + add_library(Eigen3::Eigen INTERFACE IMPORTED) + set_target_properties(Eigen3::Eigen PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${EIGEN3_INCLUDE_DIR}") +endif() diff --git a/cmake/modules/FindGit.cmake b/cmake/modules/FindGit.cmake new file mode 100644 index 0000000..2d82142 --- /dev/null +++ b/cmake/modules/FindGit.cmake @@ -0,0 +1,46 @@ +# The module defines the following variables: +# GIT_EXECUTABLE - path to git command line client +# GIT_FOUND - true if the command line client was found +# Example usage: +# find_package(Git) +# if(GIT_FOUND) +# message("git found: ${GIT_EXECUTABLE}") +# endif() + +#============================================================================= +# Copyright 2010 Kitware, Inc. +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distributed this file outside of CMake, substitute the full +# License text for the above reference.) + +# Look for 'git' or 'eg' (easy git) +# +set(git_names git eg) + +# Prefer .cmd variants on Windows unless running in a Makefile +# in the MSYS shell. +# +if(WIN32) + if(NOT CMAKE_GENERATOR MATCHES "MSYS") + set(git_names git.cmd git eg.cmd eg) + endif() +endif() + +find_program(GIT_EXECUTABLE + NAMES ${git_names} + DOC "git command line client" + ) +mark_as_advanced(GIT_EXECUTABLE) + +# Handle the QUIETLY and REQUIRED arguments and set GIT_FOUND to TRUE if +# all listed variables are TRUE + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(Git DEFAULT_MSG GIT_EXECUTABLE) diff --git a/cmake/modules/FindHDF5.cmake b/cmake/modules/FindHDF5.cmake new file mode 100644 index 0000000..65a825d --- /dev/null +++ b/cmake/modules/FindHDF5.cmake @@ -0,0 +1,824 @@ +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying +# file Copyright.txt or https://cmake.org/licensing for details. + +#.rst: +# FindHDF5 +# -------- +# +# Find HDF5, a library for reading and writing self describing array data. +# +# +# +# This module invokes the HDF5 wrapper compiler that should be installed +# alongside HDF5. Depending upon the HDF5 Configuration, the wrapper +# compiler is called either h5cc or h5pcc. If this succeeds, the module +# will then call the compiler with the -show argument to see what flags +# are used when compiling an HDF5 client application. +# +# The module will optionally accept the COMPONENTS argument. If no +# COMPONENTS are specified, then the find module will default to finding +# only the HDF5 C library. If one or more COMPONENTS are specified, the +# module will attempt to find the language bindings for the specified +# components. The only valid components are C, CXX, Fortran, HL, and +# Fortran_HL. If the COMPONENTS argument is not given, the module will +# attempt to find only the C bindings. +# +# On UNIX systems, this module will read the variable +# HDF5_USE_STATIC_LIBRARIES to determine whether or not to prefer a +# static link to a dynamic link for HDF5 and all of it's dependencies. +# To use this feature, make sure that the HDF5_USE_STATIC_LIBRARIES +# variable is set before the call to find_package. +# +# To provide the module with a hint about where to find your HDF5 +# installation, you can set the environment variable HDF5_ROOT. The +# Find module will then look in this path when searching for HDF5 +# executables, paths, and libraries. +# +# Both the serial and parallel HDF5 wrappers are considered and the first +# directory to contain either one will be used. In the event that both appear +# in the same directory the serial version is preferentially selected. This +# behavior can be reversed by setting the variable HDF5_PREFER_PARALLEL to +# true. +# +# In addition to finding the includes and libraries required to compile +# an HDF5 client application, this module also makes an effort to find +# tools that come with the HDF5 distribution that may be useful for +# regression testing. +# +# This module will define the following variables: +# +# :: +# +# HDF5_FOUND - true if HDF5 was found on the system +# HDF5_VERSION - HDF5 version in format Major.Minor.Release +# HDF5_INCLUDE_DIRS - Location of the hdf5 includes +# HDF5_INCLUDE_DIR - Location of the hdf5 includes (deprecated) +# HDF5_DEFINITIONS - Required compiler definitions for HDF5 +# HDF5_LIBRARIES - Required libraries for all requested bindings +# HDF5_HL_LIBRARIES - Required libraries for the HDF5 high level API for all +# bindings, if the HL component is enabled +# +# Available components are: C CXX Fortran and HL. For each enabled language +# binding, a corresponding HDF5_${LANG}_LIBRARIES variable will be defined. +# If the HL component is enabled, then an HDF5_${LANG}_HL_LIBRARIES will +# also be defined. With all components enabled, the following variables will be defined: +# +# :: +# +# HDF5_C_LIBRARIES - Required libraries for the HDF5 C bindings +# HDF5_CXX_LIBRARIES - Required libraries for the HDF5 C++ bindings +# HDF5_Fortran_LIBRARIES - Required libraries for the HDF5 Fortran bindings +# HDF5_C_HL_LIBRARIES - Required libraries for the high level C bindings +# HDF5_CXX_HL_LIBRARIES - Required libraries for the high level C++ bindings +# HDF5_Fortran_HL_LIBRARIES - Required libraries for the high level Fortran +# bindings. +# +# HDF5_IS_PARALLEL - Whether or not HDF5 was found with parallel IO support +# HDF5_C_COMPILER_EXECUTABLE - the path to the HDF5 C wrapper compiler +# HDF5_CXX_COMPILER_EXECUTABLE - the path to the HDF5 C++ wrapper compiler +# HDF5_Fortran_COMPILER_EXECUTABLE - the path to the HDF5 Fortran wrapper compiler +# HDF5_C_COMPILER_EXECUTABLE_NO_INTERROGATE - path to the primary C compiler +# which is also the HDF5 wrapper +# HDF5_CXX_COMPILER_EXECUTABLE_NO_INTERROGATE - path to the primary C++ +# compiler which is also +# the HDF5 wrapper +# HDF5_Fortran_COMPILER_EXECUTABLE_NO_INTERROGATE - path to the primary +# Fortran compiler which +# is also the HDF5 wrapper +# HDF5_DIFF_EXECUTABLE - the path to the HDF5 dataset comparison tool +# +# The following variable can be set to guide the search for HDF5 libraries and includes: +# +# HDF5_ROOT + +# This module is maintained by Will Dicharry . + +include(${CMAKE_CURRENT_LIST_DIR}/SelectLibraryConfigurations.cmake) +include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake) + +# List of the valid HDF5 components +set(HDF5_VALID_LANGUAGE_BINDINGS C CXX Fortran) + +# Validate the list of find components. +if(NOT HDF5_FIND_COMPONENTS) + set(HDF5_LANGUAGE_BINDINGS "C") +else() + set(HDF5_LANGUAGE_BINDINGS) + # add the extra specified components, ensuring that they are valid. + set(FIND_HL OFF) + foreach(component IN LISTS HDF5_FIND_COMPONENTS) + list(FIND HDF5_VALID_LANGUAGE_BINDINGS ${component} component_location) + if(NOT component_location EQUAL -1) + list(APPEND HDF5_LANGUAGE_BINDINGS ${component}) + elseif(component STREQUAL "HL") + set(FIND_HL ON) + elseif(component STREQUAL "Fortran_HL") # only for compatibility + list(APPEND HDF5_LANGUAGE_BINDINGS Fortran) + set(FIND_HL ON) + set(HDF5_FIND_REQUIRED_Fortran_HL False) + set(HDF5_FIND_REQUIRED_Fortran True) + set(HDF5_FIND_REQUIRED_HL True) + else() + message(FATAL_ERROR "${component} is not a valid HDF5 component.") + endif() + endforeach() + if(NOT HDF5_LANGUAGE_BINDINGS) + get_property(__langs GLOBAL PROPERTY ENABLED_LANGUAGES) + foreach(__lang IN LISTS __langs) + if(__lang MATCHES "^(C|CXX|Fortran)$") + list(APPEND HDF5_LANGUAGE_BINDINGS ${__lang}) + endif() + endforeach() + endif() + list(REMOVE_ITEM HDF5_FIND_COMPONENTS Fortran_HL) # replaced by Fortran and HL + list(REMOVE_DUPLICATES HDF5_LANGUAGE_BINDINGS) +endif() + +# Determine whether to search for serial or parallel executable first +if(HDF5_PREFER_PARALLEL) + set(HDF5_C_COMPILER_NAMES h5pcc h5cc) + set(HDF5_CXX_COMPILER_NAMES h5pc++ h5c++) + set(HDF5_Fortran_COMPILER_NAMES h5pfc h5fc) +else() + set(HDF5_C_COMPILER_NAMES h5cc h5pcc) + set(HDF5_CXX_COMPILER_NAMES h5c++ h5pc++) + set(HDF5_Fortran_COMPILER_NAMES h5fc h5pfc) +endif() + +# We may have picked up some duplicates in various lists during the above +# process for the language bindings (both the C and C++ bindings depend on +# libz for example). Remove the duplicates. It appears that the default +# CMake behavior is to remove duplicates from the end of a list. However, +# for link lines, this is incorrect since unresolved symbols are searched +# for down the link line. Therefore, we reverse the list, remove the +# duplicates, and then reverse it again to get the duplicates removed from +# the beginning. +macro(_HDF5_remove_duplicates_from_beginning _list_name) + if(${_list_name}) + list(REVERSE ${_list_name}) + list(REMOVE_DUPLICATES ${_list_name}) + list(REVERSE ${_list_name}) + endif() +endmacro() + + +# Test first if the current compilers automatically wrap HDF5 + +function(_HDF5_test_regular_compiler_C success version is_parallel) + set(scratch_directory + ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/hdf5) + if(NOT ${success} OR + NOT EXISTS ${scratch_directory}/compiler_has_h5_c) + set(test_file ${scratch_directory}/cmake_hdf5_test.c) + file(WRITE ${test_file} + "#include \n" + "#include \n" + "int main(void) {\n" + " char const* info_ver = \"INFO\" \":\" H5_VERSION;\n" + " hid_t fid;\n" + " fid = H5Fcreate(\"foo.h5\",H5F_ACC_TRUNC,H5P_DEFAULT,H5P_DEFAULT);\n" + " return 0;\n" + "}") + try_compile(${success} ${scratch_directory} ${test_file} + COPY_FILE ${scratch_directory}/compiler_has_h5_c + ) + endif() + if(${success}) + file(STRINGS ${scratch_directory}/compiler_has_h5_c INFO_VER + REGEX "^INFO:([0-9]+\\.[0-9]+\\.[0-9]+)(-patch([0-9]+))?" + ) + string(REGEX MATCH "^INFO:([0-9]+\\.[0-9]+\\.[0-9]+)(-patch([0-9]+))?" + INFO_VER "${INFO_VER}" + ) + set(${version} ${CMAKE_MATCH_1}) + if(CMAKE_MATCH_3) + set(${version} ${HDF5_CXX_VERSION}.${CMAKE_MATCH_3}) + endif() + set(${version} ${${version}} PARENT_SCOPE) + + execute_process(COMMAND ${CMAKE_C_COMPILER} -showconfig + OUTPUT_VARIABLE config_output + ERROR_VARIABLE config_error + RESULT_VARIABLE config_result + ) + if(config_output MATCHES "Parallel HDF5: yes") + set(${is_parallel} TRUE PARENT_SCOPE) + else() + set(${is_parallel} FALSE PARENT_SCOPE) + endif() + endif() +endfunction() + +function(_HDF5_test_regular_compiler_CXX success version is_parallel) + set(scratch_directory ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/hdf5) + if(NOT ${success} OR + NOT EXISTS ${scratch_directory}/compiler_has_h5_cxx) + set(test_file ${scratch_directory}/cmake_hdf5_test.cxx) + file(WRITE ${test_file} + "#include \n" + "#ifndef H5_NO_NAMESPACE\n" + "using namespace H5;\n" + "#endif\n" + "int main(int argc, char **argv) {\n" + " char const* info_ver = \"INFO\" \":\" H5_VERSION;\n" + " H5File file(\"foo.h5\", H5F_ACC_TRUNC);\n" + " return 0;\n" + "}") + try_compile(${success} ${scratch_directory} ${test_file} + COPY_FILE ${scratch_directory}/compiler_has_h5_cxx + ) + endif() + if(${success}) + file(STRINGS ${scratch_directory}/compiler_has_h5_cxx INFO_VER + REGEX "^INFO:([0-9]+\\.[0-9]+\\.[0-9]+)(-patch([0-9]+))?" + ) + string(REGEX MATCH "^INFO:([0-9]+\\.[0-9]+\\.[0-9]+)(-patch([0-9]+))?" + INFO_VER "${INFO_VER}" + ) + set(${version} ${CMAKE_MATCH_1}) + if(CMAKE_MATCH_3) + set(${version} ${HDF5_CXX_VERSION}.${CMAKE_MATCH_3}) + endif() + set(${version} ${${version}} PARENT_SCOPE) + + execute_process(COMMAND ${CMAKE_CXX_COMPILER} -showconfig + OUTPUT_VARIABLE config_output + ERROR_VARIABLE config_error + RESULT_VARIABLE config_result + ) + if(config_output MATCHES "Parallel HDF5: yes") + set(${is_parallel} TRUE PARENT_SCOPE) + else() + set(${is_parallel} FALSE PARENT_SCOPE) + endif() + endif() +endfunction() + +function(_HDF5_test_regular_compiler_Fortran success is_parallel) + if(NOT ${success}) + set(scratch_directory + ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/hdf5) + set(test_file ${scratch_directory}/cmake_hdf5_test.f90) + file(WRITE ${test_file} + "program hdf5_hello\n" + " use hdf5\n" + " use h5lt\n" + " use h5ds\n" + " integer error\n" + " call h5open_f(error)\n" + " call h5close_f(error)\n" + "end\n") + try_compile(${success} ${scratch_directory} ${test_file}) + if(${success}) + execute_process(COMMAND ${CMAKE_Fortran_COMPILER} -showconfig + OUTPUT_VARIABLE config_output + ERROR_VARIABLE config_error + RESULT_VARIABLE config_result + ) + if(config_output MATCHES "Parallel HDF5: yes") + set(${is_parallel} TRUE PARENT_SCOPE) + else() + set(${is_parallel} FALSE PARENT_SCOPE) + endif() + endif() + endif() +endfunction() + +# Invoke the HDF5 wrapper compiler. The compiler return value is stored to the +# return_value argument, the text output is stored to the output variable. +macro( _HDF5_invoke_compiler language output return_value version is_parallel) + set(${version}) + if(HDF5_USE_STATIC_LIBRARIES) + set(lib_type_args -noshlib) + else() + set(lib_type_args -shlib) + endif() + set(scratch_dir ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/hdf5) + if("${language}" STREQUAL "C") + set(test_file ${scratch_dir}/cmake_hdf5_test.c) + elseif("${language}" STREQUAL "CXX") + set(test_file ${scratch_dir}/cmake_hdf5_test.cxx) + elseif("${language}" STREQUAL "Fortran") + set(test_file ${scratch_dir}/cmake_hdf5_test.f90) + endif() + exec_program( ${HDF5_${language}_COMPILER_EXECUTABLE} + ARGS -show ${lib_type_args} ${test_file} + OUTPUT_VARIABLE ${output} + RETURN_VALUE ${return_value} + ) + if(NOT ${${return_value}} EQUAL 0) + message(STATUS + "Unable to determine HDF5 ${language} flags from HDF5 wrapper.") + endif() + exec_program( ${HDF5_${language}_COMPILER_EXECUTABLE} + ARGS -showconfig + OUTPUT_VARIABLE config_output + RETURN_VALUE config_return + ) + if(NOT ${return_value} EQUAL 0) + message( STATUS + "Unable to determine HDF5 ${language} version from HDF5 wrapper.") + endif() + string(REGEX MATCH "HDF5 Version: ([a-zA-Z0-9\\.\\-]*)" version_match "${config_output}") + if(version_match) + string(REPLACE "HDF5 Version: " "" ${version} "${version_match}") + string(REPLACE "-patch" "." ${version} "${${version}}") + endif() + if(config_output MATCHES "Parallel HDF5: yes") + set(${is_parallel} TRUE) + else() + set(${is_parallel} FALSE) + endif() +endmacro() + +# Parse a compile line for definitions, includes, library paths, and libraries. +macro( _HDF5_parse_compile_line + compile_line_var + include_paths + definitions + library_paths + libraries + libraries_hl) + + if(UNIX) + separate_arguments(_HDF5_COMPILE_ARGS UNIX_COMMAND "${${compile_line_var}}") + else() + separate_arguments(_HDF5_COMPILE_ARGS WINDOWS_COMMAND "${${compile_line_var}}") + endif() + + foreach(arg IN LISTS _HDF5_COMPILE_ARGS) + if("${arg}" MATCHES "^-I(.*)$") + # include directory + list(APPEND ${include_paths} "${CMAKE_MATCH_1}") + elseif("${arg}" MATCHES "^-D(.*)$") + # compile definition + list(APPEND ${definitions} "${CMAKE_MATCH_1}") + elseif("${arg}" MATCHES "^-L(.*)$") + # library search path + list(APPEND ${library_paths} "${CMAKE_MATCH_1}") + elseif("${arg}" MATCHES "^-l(hdf5.*hl.*)$") + # library name (hl) + list(APPEND ${libraries_hl} "${CMAKE_MATCH_1}") + elseif("${arg}" MATCHES "^-l(.*)$") + # library name + list(APPEND ${libraries} "${CMAKE_MATCH_1}") + elseif("${arg}" MATCHES "^(.:)?[/\\].*\\.(a|so|dylib|sl|lib)$") + # library file + if(NOT EXISTS "${arg}") + continue() + endif() + get_filename_component(_HDF5_LPATH "${arg}" DIRECTORY) + get_filename_component(_HDF5_LNAME "${arg}" NAME_WE) + string(REGEX REPLACE "^lib" "" _HDF5_LNAME "${_HDF5_LNAME}") + list(APPEND ${library_paths} "${_HDF5_LPATH}") + if(_HDF5_LNAME MATCHES "hdf5.*hl") + list(APPEND ${libraries_hl} "${_HDF5_LNAME}") + else() + list(APPEND ${libraries} "${_HDF5_LNAME}") + endif() + endif() + endforeach() +endmacro() + +if(NOT HDF5_ROOT) + set(HDF5_ROOT $ENV{HDF5_ROOT}) +endif() +if(HDF5_ROOT) + set(_HDF5_SEARCH_OPTS NO_DEFAULT_PATH) +else() + set(_HDF5_SEARCH_OPTS) +endif() + +# Try to find HDF5 using an installed hdf5-config.cmake +if(NOT HDF5_FOUND) + find_package(HDF5 QUIET NO_MODULE + HINTS ${HDF5_ROOT} + ${_HDF5_SEARCH_OPTS} + ) + if( HDF5_FOUND) + set(HDF5_IS_PARALLEL ${HDF5_ENABLE_PARALLEL}) + set(HDF5_INCLUDE_DIRS ${HDF5_INCLUDE_DIR}) + set(HDF5_LIBRARIES) + set(HDF5_C_TARGET hdf5) + set(HDF5_C_HL_TARGET hdf5_hl) + set(HDF5_CXX_TARGET hdf5_cpp) + set(HDF5_CXX_HL_TARGET hdf5_hl_cpp) + set(HDF5_Fortran_TARGET hdf5_fortran) + set(HDF5_Fortran_HL_TARGET hdf5_hl_fortran) + if(HDF5_USE_STATIC_LIBRARIES) + set(_suffix "-static") + else() + set(_suffix "-shared") + endif() + foreach(_lang ${HDF5_LANGUAGE_BINDINGS}) + + #Older versions of hdf5 don't have a static/shared suffix so + #if we detect that occurrence clear the suffix + if(_suffix AND NOT TARGET ${HDF5_${_lang}_TARGET}${_suffix}) + if(NOT TARGET ${HDF5_${_lang}_TARGET}) + #cant find this component with our without the suffix + #so bail out, and let the following locate HDF5 + set(HDF5_FOUND FALSE) + break() + endif() + set(_suffix "") + endif() + + get_target_property(_lang_location ${HDF5_${_lang}_TARGET}${_suffix} LOCATION) + if( _lang_location ) + set(HDF5_${_lang}_LIBRARY ${_lang_location} CACHE PATH + "HDF5 ${_lang} library" ) + mark_as_advanced(HDF5_${_lang}_LIBRARY) + list(APPEND HDF5_LIBRARIES ${HDF5_${_lang}_TARGET}${_suffix}) + set(HDF5_${_lang}_LIBRARIES ${HDF5_${_lang}_TARGET}${_suffix}) + set(HDF5_${_lang}_FOUND True) + endif() + if(FIND_HL) + get_target_property(_lang_hl_location ${HDF5_${_lang}_HL_TARGET}${_suffix} LOCATION) + if( _lang_hl_location ) + set(HDF5_${_lang}_HL_LIBRARY ${_lang_hl_location} CACHE PATH + "HDF5 ${_lang} HL library" ) + mark_as_advanced(HDF5_${_lang}_HL_LIBRARY) + list(APPEND HDF5_HL_LIBRARIES ${HDF5_${_lang}_TARGET}${_suffix}) + set(HDF5_${_lang}_HL_LIBRARIES ${HDF5_${_lang}_TARGET}${_suffix}) + set(HDF5_HL_FOUND True) + endif() + endif() + endforeach() + endif() +endif() + +if(NOT HDF5_FOUND) + set(_HDF5_NEED_TO_SEARCH False) + set(HDF5_COMPILER_NO_INTERROGATE True) + # Only search for languages we've enabled + foreach(__lang IN LISTS HDF5_LANGUAGE_BINDINGS) + # First check to see if our regular compiler is one of wrappers + if(__lang STREQUAL "C") + _HDF5_test_regular_compiler_C( + HDF5_${__lang}_COMPILER_NO_INTERROGATE + HDF5_${__lang}_VERSION + HDF5_${__lang}_IS_PARALLEL) + elseif(__lang STREQUAL "CXX") + _HDF5_test_regular_compiler_CXX( + HDF5_${__lang}_COMPILER_NO_INTERROGATE + HDF5_${__lang}_VERSION + HDF5_${__lang}_IS_PARALLEL) + elseif(__lang STREQUAL "Fortran") + _HDF5_test_regular_compiler_Fortran( + HDF5_${__lang}_COMPILER_NO_INTERROGATE + HDF5_${__lang}_IS_PARALLEL) + else() + continue() + endif() + if(HDF5_${__lang}_COMPILER_NO_INTERROGATE) + message(STATUS "HDF5: Using hdf5 compiler wrapper for all ${__lang} compiling") + set(HDF5_${__lang}_FOUND True) + set(HDF5_${__lang}_COMPILER_EXECUTABLE_NO_INTERROGATE + "${CMAKE_${__lang}_COMPILER}" + CACHE FILEPATH "HDF5 ${__lang} compiler wrapper") + set(HDF5_${__lang}_DEFINITIONS) + set(HDF5_${__lang}_INCLUDE_DIRS) + set(HDF5_${__lang}_LIBRARIES) + set(HDF5_${__lang}_HL_LIBRARIES) + + mark_as_advanced(HDF5_${__lang}_COMPILER_EXECUTABLE_NO_INTERROGATE) + mark_as_advanced(HDF5_${__lang}_DEFINITIONS) + mark_as_advanced(HDF5_${__lang}_INCLUDE_DIRS) + mark_as_advanced(HDF5_${__lang}_LIBRARIES) + mark_as_advanced(HDF5_${__lang}_HL_LIBRARIES) + + set(HDF5_${__lang}_FOUND True) + set(HDF5_HL_FOUND True) + else() + set(HDF5_COMPILER_NO_INTERROGATE False) + # If this language isn't using the wrapper, then try to seed the + # search options with the wrapper + find_program(HDF5_${__lang}_COMPILER_EXECUTABLE + NAMES ${HDF5_${__lang}_COMPILER_NAMES} NAMES_PER_DIR + HINTS ${HDF5_ROOT} + PATH_SUFFIXES bin Bin + DOC "HDF5 ${__lang} Wrapper compiler. Used only to detect HDF5 compile flags." + ${_HDF5_SEARCH_OPTS} + ) + mark_as_advanced( HDF5_${__lang}_COMPILER_EXECUTABLE ) + unset(HDF5_${__lang}_COMPILER_NAMES) + + if(HDF5_${__lang}_COMPILER_EXECUTABLE) + _HDF5_invoke_compiler(${__lang} HDF5_${__lang}_COMPILE_LINE + HDF5_${__lang}_RETURN_VALUE HDF5_${__lang}_VERSION HDF5_${__lang}_IS_PARALLEL) + if(HDF5_${__lang}_RETURN_VALUE EQUAL 0) + message(STATUS "HDF5: Using hdf5 compiler wrapper to determine ${__lang} configuration") + _HDF5_parse_compile_line( HDF5_${__lang}_COMPILE_LINE + HDF5_${__lang}_INCLUDE_DIRS + HDF5_${__lang}_DEFINITIONS + HDF5_${__lang}_LIBRARY_DIRS + HDF5_${__lang}_LIBRARY_NAMES + HDF5_${__lang}_HL_LIBRARY_NAMES + ) + set(HDF5_${__lang}_LIBRARIES) + + foreach(L IN LISTS HDF5_${__lang}_LIBRARY_NAMES) + set(_HDF5_SEARCH_NAMES_LOCAL) + if(x"${L}" MATCHES "hdf5") + # hdf5 library + set(_HDF5_SEARCH_OPTS_LOCAL ${_HDF5_SEARCH_OPTS}) + if(UNIX AND HDF5_USE_STATIC_LIBRARIES) + set(_HDF5_SEARCH_NAMES_LOCAL lib${L}.a) + endif() + else() + # external library + set(_HDF5_SEARCH_OPTS_LOCAL) + endif() + find_library(HDF5_${__lang}_LIBRARY_${L} + NAMES ${_HDF5_SEARCH_NAMES_LOCAL} ${L} NAMES_PER_DIR + HINTS ${HDF5_${__lang}_LIBRARY_DIRS} + ${HDF5_ROOT} + ${_HDF5_SEARCH_OPTS_LOCAL} + ) + unset(_HDF5_SEARCH_OPTS_LOCAL) + unset(_HDF5_SEARCH_NAMES_LOCAL) + if(HDF5_${__lang}_LIBRARY_${L}) + list(APPEND HDF5_${__lang}_LIBRARIES ${HDF5_${__lang}_LIBRARY_${L}}) + else() + list(APPEND HDF5_${__lang}_LIBRARIES ${L}) + endif() + endforeach() + if(FIND_HL) + set(HDF5_${__lang}_HL_LIBRARIES) + foreach(L IN LISTS HDF5_${__lang}_HL_LIBRARY_NAMES) + set(_HDF5_SEARCH_NAMES_LOCAL) + if("x${L}" MATCHES "hdf5") + # hdf5 library + set(_HDF5_SEARCH_OPTS_LOCAL ${_HDF5_SEARCH_OPTS}) + if(UNIX AND HDF5_USE_STATIC_LIBRARIES) + set(_HDF5_SEARCH_NAMES_LOCAL lib${L}.a) + endif() + else() + # external library + set(_HDF5_SEARCH_OPTS_LOCAL) + endif() + find_library(HDF5_${__lang}_LIBRARY_${L} + NAMES ${_HDF5_SEARCH_NAMES_LOCAL} ${L} NAMES_PER_DIR + HINTS ${HDF5_${__lang}_LIBRARY_DIRS} + ${HDF5_ROOT} + ${_HDF5_SEARCH_OPTS_LOCAL} + ) + unset(_HDF5_SEARCH_OPTS_LOCAL) + unset(_HDF5_SEARCH_NAMES_LOCAL) + if(HDF5_${__lang}_LIBRARY_${L}) + list(APPEND HDF5_${__lang}_HL_LIBRARIES ${HDF5_${__lang}_LIBRARY_${L}}) + else() + list(APPEND HDF5_${__lang}_HL_LIBRARIES ${L}) + endif() + endforeach() + set(HDF5_HL_FOUND True) + endif() + + set(HDF5_${__lang}_FOUND True) + mark_as_advanced(HDF5_${__lang}_DEFINITIONS) + mark_as_advanced(HDF5_${__lang}_INCLUDE_DIRS) + mark_as_advanced(HDF5_${__lang}_LIBRARIES) + _HDF5_remove_duplicates_from_beginning(HDF5_${__lang}_DEFINITIONS) + _HDF5_remove_duplicates_from_beginning(HDF5_${__lang}_INCLUDE_DIRS) + _HDF5_remove_duplicates_from_beginning(HDF5_${__lang}_LIBRARIES) + _HDF5_remove_duplicates_from_beginning(HDF5_${__lang}_HL_LIBRARIES) + else() + set(_HDF5_NEED_TO_SEARCH True) + endif() + else() + set(_HDF5_NEED_TO_SEARCH True) + endif() + endif() + if(HDF5_${__lang}_VERSION) + if(NOT HDF5_VERSION) + set(HDF5_VERSION ${HDF5_${__lang}_VERSION}) + elseif(NOT HDF5_VERSION VERSION_EQUAL HDF5_${__lang}_VERSION) + message(WARNING "HDF5 Version found for language ${__lang}, ${HDF5_${__lang}_VERSION} is different than previously found version ${HDF5_VERSION}") + endif() + endif() + if(DEFINED HDF5_${__lang}_IS_PARALLEL) + if(NOT DEFINED HDF5_IS_PARALLEL) + set(HDF5_IS_PARALLEL ${HDF5_${__lang}_IS_PARALLEL}) + elseif(NOT HDF5_IS_PARALLEL AND HDF5_${__lang}_IS_PARALLEL) + message(WARNING "HDF5 found for language ${__lang} is parallel but previously found language is not parallel.") + elseif(HDF5_IS_PARALLEL AND NOT HDF5_${__lang}_IS_PARALLEL) + message(WARNING "HDF5 found for language ${__lang} is not parallel but previously found language is parallel.") + endif() + endif() + endforeach() +else() + set(_HDF5_NEED_TO_SEARCH True) +endif() + +if(NOT HDF5_FOUND AND HDF5_COMPILER_NO_INTERROGATE) + # No arguments necessary, all languages can use the compiler wrappers + set(HDF5_FOUND True) + set(HDF5_METHOD "Included by compiler wrappers") + set(HDF5_REQUIRED_VARS HDF5_METHOD) +elseif(NOT HDF5_FOUND AND NOT _HDF5_NEED_TO_SEARCH) + # Compiler wrappers aren't being used by the build but were found and used + # to determine necessary include and library flags + set(HDF5_INCLUDE_DIRS) + set(HDF5_LIBRARIES) + set(HDF5_HL_LIBRARIES) + foreach(__lang IN LISTS HDF5_LANGUAGE_BINDINGS) + if(HDF5_${__lang}_FOUND) + if(NOT HDF5_${__lang}_COMPILER_NO_INTERROGATE) + list(APPEND HDF5_DEFINITIONS ${HDF5_${__lang}_DEFINITIONS}) + list(APPEND HDF5_INCLUDE_DIRS ${HDF5_${__lang}_INCLUDE_DIRS}) + list(APPEND HDF5_LIBRARIES ${HDF5_${__lang}_LIBRARIES}) + if(FIND_HL) + list(APPEND HDF5_HL_LIBRARIES ${HDF5_${__lang}_HL_LIBRARIES}) + endif() + endif() + endif() + endforeach() + _HDF5_remove_duplicates_from_beginning(HDF5_DEFINITIONS) + _HDF5_remove_duplicates_from_beginning(HDF5_INCLUDE_DIRS) + _HDF5_remove_duplicates_from_beginning(HDF5_LIBRARIES) + _HDF5_remove_duplicates_from_beginning(HDF5_HL_LIBRARIES) + set(HDF5_FOUND True) + set(HDF5_REQUIRED_VARS HDF5_LIBRARIES) + if(FIND_HL) + list(APPEND HDF5_REQUIRED_VARS HDF5_HL_LIBRARIES) + endif() +endif() + +find_program( HDF5_DIFF_EXECUTABLE + NAMES h5diff + HINTS ${HDF5_ROOT} + PATH_SUFFIXES bin Bin + ${_HDF5_SEARCH_OPTS} + DOC "HDF5 file differencing tool." ) +mark_as_advanced( HDF5_DIFF_EXECUTABLE ) + +if( NOT HDF5_FOUND ) + # seed the initial lists of libraries to find with items we know we need + set(HDF5_C_LIBRARY_NAMES hdf5) + set(HDF5_C_HL_LIBRARY_NAMES hdf5_hl) + + set(HDF5_CXX_LIBRARY_NAMES hdf5_cpp ${HDF5_C_LIBRARY_NAMES}) + set(HDF5_CXX_HL_LIBRARY_NAMES hdf5_hl_cpp ${HDF5_C_HL_LIBRARY_NAMES} ${HDF5_CXX_LIBRARY_NAMES}) + + set(HDF5_Fortran_LIBRARY_NAMES hdf5_fortran ${HDF5_C_LIBRARY_NAMES}) + set(HDF5_Fortran_HL_LIBRARY_NAMES hdf5hl_fortran ${HDF5_C_HL_LIBRARY_NAMES} ${HDF5_Fortran_LIBRARY_NAMES}) + + foreach(__lang IN LISTS HDF5_LANGUAGE_BINDINGS) + # find the HDF5 include directories + if("${__lang}" STREQUAL "Fortran") + set(HDF5_INCLUDE_FILENAME hdf5.mod) + elseif("${__lang}" STREQUAL "CXX") + set(HDF5_INCLUDE_FILENAME H5Cpp.h) + else() + set(HDF5_INCLUDE_FILENAME hdf5.h) + endif() + + find_path(HDF5_${__lang}_INCLUDE_DIR ${HDF5_INCLUDE_FILENAME} + HINTS ${HDF5_ROOT} + PATHS $ENV{HOME}/.local/include + PATH_SUFFIXES include Include + ${_HDF5_SEARCH_OPTS} + ) + mark_as_advanced(HDF5_${__lang}_INCLUDE_DIR) + list(APPEND HDF5_INCLUDE_DIRS ${HDF5_${__lang}_INCLUDE_DIR}) + + # find the HDF5 libraries + foreach(LIB IN LISTS HDF5_${__lang}_LIBRARY_NAMES) + if(UNIX AND HDF5_USE_STATIC_LIBRARIES) + # According to bug 1643 on the CMake bug tracker, this is the + # preferred method for searching for a static library. + # See https://gitlab.kitware.com/cmake/cmake/issues/1643. We search + # first for the full static library name, but fall back to a + # generic search on the name if the static search fails. + set( THIS_LIBRARY_SEARCH_DEBUG + lib${LIB}d.a lib${LIB}_debug.a ${LIB}d ${LIB}_debug + lib${LIB}d-static.a lib${LIB}_debug-static.a ${LIB}d-static ${LIB}_debug-static ) + set( THIS_LIBRARY_SEARCH_RELEASE lib${LIB}.a ${LIB} lib${LIB}-static.a ${LIB}-static) + else() + set( THIS_LIBRARY_SEARCH_DEBUG ${LIB}d ${LIB}_debug ${LIB}d-shared ${LIB}_debug-shared) + set( THIS_LIBRARY_SEARCH_RELEASE ${LIB} ${LIB}-shared) + endif() + find_library(HDF5_${LIB}_LIBRARY_DEBUG + NAMES ${THIS_LIBRARY_SEARCH_DEBUG} + HINTS ${HDF5_ROOT} PATH_SUFFIXES lib Lib + ${_HDF5_SEARCH_OPTS} + ) + find_library( HDF5_${LIB}_LIBRARY_RELEASE + NAMES ${THIS_LIBRARY_SEARCH_RELEASE} + HINTS ${HDF5_ROOT} PATH_SUFFIXES lib Lib + ${_HDF5_SEARCH_OPTS} + ) + select_library_configurations( HDF5_${LIB} ) + list(APPEND HDF5_${__lang}_LIBRARIES ${HDF5_${LIB}_LIBRARY}) + endforeach() + if(HDF5_${__lang}_LIBRARIES) + set(HDF5_${__lang}_FOUND True) + endif() + + # Append the libraries for this language binding to the list of all + # required libraries. + list(APPEND HDF5_LIBRARIES ${HDF5_${__lang}_LIBRARIES}) + + if(FIND_HL) + foreach(LIB IN LISTS HDF5_${__lang}_HL_LIBRARY_NAMES) + if(UNIX AND HDF5_USE_STATIC_LIBRARIES) + # According to bug 1643 on the CMake bug tracker, this is the + # preferred method for searching for a static library. + # See https://gitlab.kitware.com/cmake/cmake/issues/1643. We search + # first for the full static library name, but fall back to a + # generic search on the name if the static search fails. + set( THIS_LIBRARY_SEARCH_DEBUG + lib${LIB}d.a lib${LIB}_debug.a ${LIB}d ${LIB}_debug + lib${LIB}d-static.a lib${LIB}_debug-static.a ${LIB}d-static ${LIB}_debug-static ) + set( THIS_LIBRARY_SEARCH_RELEASE lib${LIB}.a ${LIB} lib${LIB}-static.a ${LIB}-static) + else() + set( THIS_LIBRARY_SEARCH_DEBUG ${LIB}d ${LIB}_debug ${LIB}d-shared ${LIB}_debug-shared) + set( THIS_LIBRARY_SEARCH_RELEASE ${LIB} ${LIB}-shared) + endif() + find_library(HDF5_${LIB}_LIBRARY_DEBUG + NAMES ${THIS_LIBRARY_SEARCH_DEBUG} + HINTS ${HDF5_ROOT} PATH_SUFFIXES lib Lib + ${_HDF5_SEARCH_OPTS} + ) + find_library( HDF5_${LIB}_LIBRARY_RELEASE + NAMES ${THIS_LIBRARY_SEARCH_RELEASE} + HINTS ${HDF5_ROOT} PATH_SUFFIXES lib Lib + ${_HDF5_SEARCH_OPTS} + ) + select_library_configurations( HDF5_${LIB} ) + list(APPEND HDF5_${__lang}_HL_LIBRARIES ${HDF5_${LIB}_LIBRARY}) + endforeach() + + # Append the libraries for this language binding to the list of all + # required libraries. + list(APPEND HDF5_HL_LIBRARIES ${HDF5_${__lang}_HL_LIBRARIES}) + endif() + endforeach() + if(FIND_HL AND HDF5_HL_LIBRARIES) + set(HDF5_HL_FOUND True) + endif() + + _HDF5_remove_duplicates_from_beginning(HDF5_INCLUDE_DIRS) + _HDF5_remove_duplicates_from_beginning(HDF5_LIBRARIES) + _HDF5_remove_duplicates_from_beginning(HDF5_HL_LIBRARIES) + + # If the HDF5 include directory was found, open H5pubconf.h to determine if + # HDF5 was compiled with parallel IO support + set( HDF5_IS_PARALLEL FALSE ) + set( HDF5_VERSION "" ) + foreach( _dir IN LISTS HDF5_INCLUDE_DIRS ) + foreach(_hdr "${_dir}/H5pubconf.h" "${_dir}/H5pubconf-64.h" "${_dir}/H5pubconf-32.h") + if( EXISTS "${_hdr}" ) + file( STRINGS "${_hdr}" + HDF5_HAVE_PARALLEL_DEFINE + REGEX "HAVE_PARALLEL 1" ) + if( HDF5_HAVE_PARALLEL_DEFINE ) + set( HDF5_IS_PARALLEL TRUE ) + endif() + unset(HDF5_HAVE_PARALLEL_DEFINE) + + file( STRINGS "${_hdr}" + HDF5_VERSION_DEFINE + REGEX "^[ \t]*#[ \t]*define[ \t]+H5_VERSION[ \t]+" ) + if( "${HDF5_VERSION_DEFINE}" MATCHES + "H5_VERSION[ \t]+\"([0-9]+\\.[0-9]+\\.[0-9]+)(-patch([0-9]+))?\"" ) + set( HDF5_VERSION "${CMAKE_MATCH_1}" ) + if( CMAKE_MATCH_3 ) + set( HDF5_VERSION ${HDF5_VERSION}.${CMAKE_MATCH_3}) + endif() + endif() + unset(HDF5_VERSION_DEFINE) + endif() + endforeach() + endforeach() + set( HDF5_IS_PARALLEL ${HDF5_IS_PARALLEL} CACHE BOOL + "HDF5 library compiled with parallel IO support" ) + mark_as_advanced( HDF5_IS_PARALLEL ) + + set(HDF5_REQUIRED_VARS HDF5_LIBRARIES HDF5_INCLUDE_DIRS) + if(FIND_HL) + list(APPEND HDF5_REQUIRED_VARS HDF5_HL_LIBRARIES) + endif() +endif() + +# For backwards compatibility we set HDF5_INCLUDE_DIR to the value of +# HDF5_INCLUDE_DIRS +if( HDF5_INCLUDE_DIRS ) + set( HDF5_INCLUDE_DIR "${HDF5_INCLUDE_DIRS}" ) +endif() + +# If HDF5_REQUIRED_VARS is empty at this point, then it's likely that +# something external is trying to explicitly pass already found +# locations +if(NOT HDF5_REQUIRED_VARS) + set(HDF5_REQUIRED_VARS HDF5_LIBRARIES HDF5_INCLUDE_DIRS) +endif() + +find_package_handle_standard_args(HDF5 + REQUIRED_VARS ${HDF5_REQUIRED_VARS} + VERSION_VAR HDF5_VERSION + HANDLE_COMPONENTS +) + +unset(_HDF5_SEARCH_OPTS) diff --git a/cmake/modules/FindPackageHandleStandardArgs.cmake b/cmake/modules/FindPackageHandleStandardArgs.cmake new file mode 100644 index 0000000..b77925d --- /dev/null +++ b/cmake/modules/FindPackageHandleStandardArgs.cmake @@ -0,0 +1,385 @@ +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying +# file Copyright.txt or https://cmake.org/licensing for details. + +#[=======================================================================[.rst: +FindPackageHandleStandardArgs +----------------------------- + +This module provides a function intended to be used in :ref:`Find Modules` +implementing :command:`find_package()` calls. It handles the +``REQUIRED``, ``QUIET`` and version-related arguments of ``find_package``. +It also sets the ``_FOUND`` variable. The package is +considered found if all variables listed contain valid results, e.g. +valid filepaths. + +.. command:: find_package_handle_standard_args + + There are two signatures:: + + find_package_handle_standard_args( + (DEFAULT_MSG|) + ... + ) + + find_package_handle_standard_args( + [FOUND_VAR ] + [REQUIRED_VARS ...] + [VERSION_VAR ] + [HANDLE_COMPONENTS] + [CONFIG_MODE] + [FAIL_MESSAGE ] + ) + + The ``_FOUND`` variable will be set to ``TRUE`` if all + the variables ``...`` are valid and any optional + constraints are satisfied, and ``FALSE`` otherwise. A success or + failure message may be displayed based on the results and on + whether the ``REQUIRED`` and/or ``QUIET`` option was given to + the :command:`find_package` call. + + The options are: + + ``(DEFAULT_MSG|)`` + In the simple signature this specifies the failure message. + Use ``DEFAULT_MSG`` to ask for a default message to be computed + (recommended). Not valid in the full signature. + + ``FOUND_VAR `` + Obsolete. Specifies either ``_FOUND`` or + ``_FOUND`` as the result variable. This exists only + for compatibility with older versions of CMake and is now ignored. + Result variables of both names are always set for compatibility. + + ``REQUIRED_VARS ...`` + Specify the variables which are required for this package. + These may be named in the generated failure message asking the + user to set the missing variable values. Therefore these should + typically be cache entries such as ``FOO_LIBRARY`` and not output + variables like ``FOO_LIBRARIES``. + + ``VERSION_VAR `` + Specify the name of a variable that holds the version of the package + that has been found. This version will be checked against the + (potentially) specified required version given to the + :command:`find_package` call, including its ``EXACT`` option. + The default messages include information about the required + version and the version which has been actually found, both + if the version is ok or not. + + ``HANDLE_COMPONENTS`` + Enable handling of package components. In this case, the command + will report which components have been found and which are missing, + and the ``_FOUND`` variable will be set to ``FALSE`` + if any of the required components (i.e. not the ones listed after + the ``OPTIONAL_COMPONENTS`` option of :command:`find_package`) are + missing. + + ``CONFIG_MODE`` + Specify that the calling find module is a wrapper around a + call to ``find_package( NO_MODULE)``. This implies + a ``VERSION_VAR`` value of ``_VERSION``. The command + will automatically check whether the package configuration file + was found. + + ``FAIL_MESSAGE `` + Specify a custom failure message instead of using the default + generated message. Not recommended. + +Example for the simple signature: + +.. code-block:: cmake + + find_package_handle_standard_args(LibXml2 DEFAULT_MSG + LIBXML2_LIBRARY LIBXML2_INCLUDE_DIR) + +The ``LibXml2`` package is considered to be found if both +``LIBXML2_LIBRARY`` and ``LIBXML2_INCLUDE_DIR`` are valid. +Then also ``LibXml2_FOUND`` is set to ``TRUE``. If it is not found +and ``REQUIRED`` was used, it fails with a +:command:`message(FATAL_ERROR)`, independent whether ``QUIET`` was +used or not. If it is found, success will be reported, including +the content of the first ````. On repeated CMake runs, +the same message will not be printed again. + +Example for the full signature: + +.. code-block:: cmake + + find_package_handle_standard_args(LibArchive + REQUIRED_VARS LibArchive_LIBRARY LibArchive_INCLUDE_DIR + VERSION_VAR LibArchive_VERSION) + +In this case, the ``LibArchive`` package is considered to be found if +both ``LibArchive_LIBRARY`` and ``LibArchive_INCLUDE_DIR`` are valid. +Also the version of ``LibArchive`` will be checked by using the version +contained in ``LibArchive_VERSION``. Since no ``FAIL_MESSAGE`` is given, +the default messages will be printed. + +Another example for the full signature: + +.. code-block:: cmake + + find_package(Automoc4 QUIET NO_MODULE HINTS /opt/automoc4) + find_package_handle_standard_args(Automoc4 CONFIG_MODE) + +In this case, a ``FindAutmoc4.cmake`` module wraps a call to +``find_package(Automoc4 NO_MODULE)`` and adds an additional search +directory for ``automoc4``. Then the call to +``find_package_handle_standard_args`` produces a proper success/failure +message. +#]=======================================================================] + +include(${CMAKE_CURRENT_LIST_DIR}/FindPackageMessage.cmake) + +# internal helper macro +macro(_FPHSA_FAILURE_MESSAGE _msg) + if (${_NAME}_FIND_REQUIRED) + message(FATAL_ERROR "${_msg}") + else () + if (NOT ${_NAME}_FIND_QUIETLY) + message(STATUS "${_msg}") + endif () + endif () +endmacro() + + +# internal helper macro to generate the failure message when used in CONFIG_MODE: +macro(_FPHSA_HANDLE_FAILURE_CONFIG_MODE) + # _CONFIG is set, but FOUND is false, this means that some other of the REQUIRED_VARS was not found: + if(${_NAME}_CONFIG) + _FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE}: missing: ${MISSING_VARS} (found ${${_NAME}_CONFIG} ${VERSION_MSG})") + else() + # If _CONSIDERED_CONFIGS is set, the config-file has been found, but no suitable version. + # List them all in the error message: + if(${_NAME}_CONSIDERED_CONFIGS) + set(configsText "") + list(LENGTH ${_NAME}_CONSIDERED_CONFIGS configsCount) + math(EXPR configsCount "${configsCount} - 1") + foreach(currentConfigIndex RANGE ${configsCount}) + list(GET ${_NAME}_CONSIDERED_CONFIGS ${currentConfigIndex} filename) + list(GET ${_NAME}_CONSIDERED_VERSIONS ${currentConfigIndex} version) + string(APPEND configsText " ${filename} (version ${version})\n") + endforeach() + if (${_NAME}_NOT_FOUND_MESSAGE) + string(APPEND configsText " Reason given by package: ${${_NAME}_NOT_FOUND_MESSAGE}\n") + endif() + _FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE} ${VERSION_MSG}, checked the following files:\n${configsText}") + + else() + # Simple case: No Config-file was found at all: + _FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE}: found neither ${_NAME}Config.cmake nor ${_NAME_LOWER}-config.cmake ${VERSION_MSG}") + endif() + endif() +endmacro() + + +function(FIND_PACKAGE_HANDLE_STANDARD_ARGS _NAME _FIRST_ARG) + +# set up the arguments for CMAKE_PARSE_ARGUMENTS and check whether we are in +# new extended or in the "old" mode: + set(options CONFIG_MODE HANDLE_COMPONENTS) + set(oneValueArgs FAIL_MESSAGE VERSION_VAR FOUND_VAR) + set(multiValueArgs REQUIRED_VARS) + set(_KEYWORDS_FOR_EXTENDED_MODE ${options} ${oneValueArgs} ${multiValueArgs} ) + list(FIND _KEYWORDS_FOR_EXTENDED_MODE "${_FIRST_ARG}" INDEX) + + if(${INDEX} EQUAL -1) + set(FPHSA_FAIL_MESSAGE ${_FIRST_ARG}) + set(FPHSA_REQUIRED_VARS ${ARGN}) + set(FPHSA_VERSION_VAR) + else() + + CMAKE_PARSE_ARGUMENTS(FPHSA "${options}" "${oneValueArgs}" "${multiValueArgs}" ${_FIRST_ARG} ${ARGN}) + + if(FPHSA_UNPARSED_ARGUMENTS) + message(FATAL_ERROR "Unknown keywords given to FIND_PACKAGE_HANDLE_STANDARD_ARGS(): \"${FPHSA_UNPARSED_ARGUMENTS}\"") + endif() + + if(NOT FPHSA_FAIL_MESSAGE) + set(FPHSA_FAIL_MESSAGE "DEFAULT_MSG") + endif() + endif() + +# now that we collected all arguments, process them + + if("x${FPHSA_FAIL_MESSAGE}" STREQUAL "xDEFAULT_MSG") + set(FPHSA_FAIL_MESSAGE "Could NOT find ${_NAME}") + endif() + + # In config-mode, we rely on the variable _CONFIG, which is set by find_package() + # when it successfully found the config-file, including version checking: + if(FPHSA_CONFIG_MODE) + list(INSERT FPHSA_REQUIRED_VARS 0 ${_NAME}_CONFIG) + list(REMOVE_DUPLICATES FPHSA_REQUIRED_VARS) + set(FPHSA_VERSION_VAR ${_NAME}_VERSION) + endif() + + if(NOT FPHSA_REQUIRED_VARS) + message(FATAL_ERROR "No REQUIRED_VARS specified for FIND_PACKAGE_HANDLE_STANDARD_ARGS()") + endif() + + list(GET FPHSA_REQUIRED_VARS 0 _FIRST_REQUIRED_VAR) + + string(TOUPPER ${_NAME} _NAME_UPPER) + string(TOLOWER ${_NAME} _NAME_LOWER) + + if(FPHSA_FOUND_VAR) + if(FPHSA_FOUND_VAR MATCHES "^${_NAME}_FOUND$" OR FPHSA_FOUND_VAR MATCHES "^${_NAME_UPPER}_FOUND$") + set(_FOUND_VAR ${FPHSA_FOUND_VAR}) + else() + message(FATAL_ERROR "The argument for FOUND_VAR is \"${FPHSA_FOUND_VAR}\", but only \"${_NAME}_FOUND\" and \"${_NAME_UPPER}_FOUND\" are valid names.") + endif() + else() + set(_FOUND_VAR ${_NAME_UPPER}_FOUND) + endif() + + # collect all variables which were not found, so they can be printed, so the + # user knows better what went wrong (#6375) + set(MISSING_VARS "") + set(DETAILS "") + # check if all passed variables are valid + set(FPHSA_FOUND_${_NAME} TRUE) + foreach(_CURRENT_VAR ${FPHSA_REQUIRED_VARS}) + if(NOT ${_CURRENT_VAR}) + set(FPHSA_FOUND_${_NAME} FALSE) + string(APPEND MISSING_VARS " ${_CURRENT_VAR}") + else() + string(APPEND DETAILS "[${${_CURRENT_VAR}}]") + endif() + endforeach() + if(FPHSA_FOUND_${_NAME}) + set(${_NAME}_FOUND TRUE) + set(${_NAME_UPPER}_FOUND TRUE) + else() + set(${_NAME}_FOUND FALSE) + set(${_NAME_UPPER}_FOUND FALSE) + endif() + + # component handling + unset(FOUND_COMPONENTS_MSG) + unset(MISSING_COMPONENTS_MSG) + + if(FPHSA_HANDLE_COMPONENTS) + foreach(comp ${${_NAME}_FIND_COMPONENTS}) + if(${_NAME}_${comp}_FOUND) + + if(NOT DEFINED FOUND_COMPONENTS_MSG) + set(FOUND_COMPONENTS_MSG "found components: ") + endif() + string(APPEND FOUND_COMPONENTS_MSG " ${comp}") + + else() + + if(NOT DEFINED MISSING_COMPONENTS_MSG) + set(MISSING_COMPONENTS_MSG "missing components: ") + endif() + string(APPEND MISSING_COMPONENTS_MSG " ${comp}") + + if(${_NAME}_FIND_REQUIRED_${comp}) + set(${_NAME}_FOUND FALSE) + string(APPEND MISSING_VARS " ${comp}") + endif() + + endif() + endforeach() + set(COMPONENT_MSG "${FOUND_COMPONENTS_MSG} ${MISSING_COMPONENTS_MSG}") + string(APPEND DETAILS "[c${COMPONENT_MSG}]") + endif() + + # version handling: + set(VERSION_MSG "") + set(VERSION_OK TRUE) + set(VERSION ${${FPHSA_VERSION_VAR}}) + + # check with DEFINED here as the requested or found version may be "0" + if (DEFINED ${_NAME}_FIND_VERSION) + if(DEFINED ${FPHSA_VERSION_VAR}) + + if(${_NAME}_FIND_VERSION_EXACT) # exact version required + # count the dots in the version string + string(REGEX REPLACE "[^.]" "" _VERSION_DOTS "${VERSION}") + # add one dot because there is one dot more than there are components + string(LENGTH "${_VERSION_DOTS}." _VERSION_DOTS) + if (_VERSION_DOTS GREATER ${_NAME}_FIND_VERSION_COUNT) + # Because of the C++ implementation of find_package() ${_NAME}_FIND_VERSION_COUNT + # is at most 4 here. Therefore a simple lookup table is used. + if (${_NAME}_FIND_VERSION_COUNT EQUAL 1) + set(_VERSION_REGEX "[^.]*") + elseif (${_NAME}_FIND_VERSION_COUNT EQUAL 2) + set(_VERSION_REGEX "[^.]*\\.[^.]*") + elseif (${_NAME}_FIND_VERSION_COUNT EQUAL 3) + set(_VERSION_REGEX "[^.]*\\.[^.]*\\.[^.]*") + else () + set(_VERSION_REGEX "[^.]*\\.[^.]*\\.[^.]*\\.[^.]*") + endif () + string(REGEX REPLACE "^(${_VERSION_REGEX})\\..*" "\\1" _VERSION_HEAD "${VERSION}") + unset(_VERSION_REGEX) + if (NOT ${_NAME}_FIND_VERSION VERSION_EQUAL _VERSION_HEAD) + set(VERSION_MSG "Found unsuitable version \"${VERSION}\", but required is exact version \"${${_NAME}_FIND_VERSION}\"") + set(VERSION_OK FALSE) + else () + set(VERSION_MSG "(found suitable exact version \"${VERSION}\")") + endif () + unset(_VERSION_HEAD) + else () + if (NOT ${_NAME}_FIND_VERSION VERSION_EQUAL VERSION) + set(VERSION_MSG "Found unsuitable version \"${VERSION}\", but required is exact version \"${${_NAME}_FIND_VERSION}\"") + set(VERSION_OK FALSE) + else () + set(VERSION_MSG "(found suitable exact version \"${VERSION}\")") + endif () + endif () + unset(_VERSION_DOTS) + + else() # minimum version specified: + if (${_NAME}_FIND_VERSION VERSION_GREATER VERSION) + set(VERSION_MSG "Found unsuitable version \"${VERSION}\", but required is at least \"${${_NAME}_FIND_VERSION}\"") + set(VERSION_OK FALSE) + else () + set(VERSION_MSG "(found suitable version \"${VERSION}\", minimum required is \"${${_NAME}_FIND_VERSION}\")") + endif () + endif() + + else() + + # if the package was not found, but a version was given, add that to the output: + if(${_NAME}_FIND_VERSION_EXACT) + set(VERSION_MSG "(Required is exact version \"${${_NAME}_FIND_VERSION}\")") + else() + set(VERSION_MSG "(Required is at least version \"${${_NAME}_FIND_VERSION}\")") + endif() + + endif() + else () + if(VERSION) + set(VERSION_MSG "(found version \"${VERSION}\")") + endif() + endif () + + if(VERSION_OK) + string(APPEND DETAILS "[v${VERSION}(${${_NAME}_FIND_VERSION})]") + else() + set(${_NAME}_FOUND FALSE) + endif() + + + # print the result: + if (${_NAME}_FOUND) + FIND_PACKAGE_MESSAGE(${_NAME} "Found ${_NAME}: ${${_FIRST_REQUIRED_VAR}} ${VERSION_MSG} ${COMPONENT_MSG}" "${DETAILS}") + else () + + if(FPHSA_CONFIG_MODE) + _FPHSA_HANDLE_FAILURE_CONFIG_MODE() + else() + if(NOT VERSION_OK) + _FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE}: ${VERSION_MSG} (found ${${_FIRST_REQUIRED_VAR}})") + else() + _FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE} (missing: ${MISSING_VARS}) ${VERSION_MSG}") + endif() + endif() + + endif () + + set(${_NAME}_FOUND ${${_NAME}_FOUND} PARENT_SCOPE) + set(${_NAME_UPPER}_FOUND ${${_NAME}_FOUND} PARENT_SCOPE) +endfunction() diff --git a/cmake/modules/FindPackageMessage.cmake b/cmake/modules/FindPackageMessage.cmake new file mode 100644 index 0000000..6821cee --- /dev/null +++ b/cmake/modules/FindPackageMessage.cmake @@ -0,0 +1,47 @@ +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying +# file Copyright.txt or https://cmake.org/licensing for details. + +#.rst: +# FindPackageMessage +# ------------------ +# +# +# +# FIND_PACKAGE_MESSAGE( "message for user" "find result details") +# +# This macro is intended to be used in FindXXX.cmake modules files. It +# will print a message once for each unique find result. This is useful +# for telling the user where a package was found. The first argument +# specifies the name (XXX) of the package. The second argument +# specifies the message to display. The third argument lists details +# about the find result so that if they change the message will be +# displayed again. The macro also obeys the QUIET argument to the +# find_package command. +# +# Example: +# +# :: +# +# if(X11_FOUND) +# FIND_PACKAGE_MESSAGE(X11 "Found X11: ${X11_X11_LIB}" +# "[${X11_X11_LIB}][${X11_INCLUDE_DIR}]") +# else() +# ... +# endif() + +function(FIND_PACKAGE_MESSAGE pkg msg details) + # Avoid printing a message repeatedly for the same find result. + if(NOT ${pkg}_FIND_QUIETLY) + string(REPLACE "\n" "" details "${details}") + set(DETAILS_VAR FIND_PACKAGE_MESSAGE_DETAILS_${pkg}) + if(NOT "${details}" STREQUAL "${${DETAILS_VAR}}") + # The message has not yet been printed. + message(STATUS "${msg}") + + # Save the find details in the cache to avoid printing the same + # message again. + set("${DETAILS_VAR}" "${details}" + CACHE INTERNAL "Details about finding ${pkg}") + endif() + endif() +endfunction() diff --git a/cmake/modules/SelectLibraryConfigurations.cmake b/cmake/modules/SelectLibraryConfigurations.cmake new file mode 100644 index 0000000..dce6f99 --- /dev/null +++ b/cmake/modules/SelectLibraryConfigurations.cmake @@ -0,0 +1,70 @@ +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying +# file Copyright.txt or https://cmake.org/licensing for details. + +#.rst: +# SelectLibraryConfigurations +# --------------------------- +# +# +# +# select_library_configurations( basename ) +# +# This macro takes a library base name as an argument, and will choose +# good values for basename_LIBRARY, basename_LIBRARIES, +# basename_LIBRARY_DEBUG, and basename_LIBRARY_RELEASE depending on what +# has been found and set. If only basename_LIBRARY_RELEASE is defined, +# basename_LIBRARY will be set to the release value, and +# basename_LIBRARY_DEBUG will be set to basename_LIBRARY_DEBUG-NOTFOUND. +# If only basename_LIBRARY_DEBUG is defined, then basename_LIBRARY will +# take the debug value, and basename_LIBRARY_RELEASE will be set to +# basename_LIBRARY_RELEASE-NOTFOUND. +# +# If the generator supports configuration types, then basename_LIBRARY +# and basename_LIBRARIES will be set with debug and optimized flags +# specifying the library to be used for the given configuration. If no +# build type has been set or the generator in use does not support +# configuration types, then basename_LIBRARY and basename_LIBRARIES will +# take only the release value, or the debug value if the release one is +# not set. + +# This macro was adapted from the FindQt4 CMake module and is maintained by Will +# Dicharry . + +macro( select_library_configurations basename ) + if(NOT ${basename}_LIBRARY_RELEASE) + set(${basename}_LIBRARY_RELEASE "${basename}_LIBRARY_RELEASE-NOTFOUND" CACHE FILEPATH "Path to a library.") + endif() + if(NOT ${basename}_LIBRARY_DEBUG) + set(${basename}_LIBRARY_DEBUG "${basename}_LIBRARY_DEBUG-NOTFOUND" CACHE FILEPATH "Path to a library.") + endif() + + if( ${basename}_LIBRARY_DEBUG AND ${basename}_LIBRARY_RELEASE AND + NOT ${basename}_LIBRARY_DEBUG STREQUAL ${basename}_LIBRARY_RELEASE AND + ( CMAKE_CONFIGURATION_TYPES OR CMAKE_BUILD_TYPE ) ) + # if the generator supports configuration types or CMAKE_BUILD_TYPE + # is set, then set optimized and debug options. + set( ${basename}_LIBRARY "" ) + foreach( _libname IN LISTS ${basename}_LIBRARY_RELEASE ) + list( APPEND ${basename}_LIBRARY optimized "${_libname}" ) + endforeach() + foreach( _libname IN LISTS ${basename}_LIBRARY_DEBUG ) + list( APPEND ${basename}_LIBRARY debug "${_libname}" ) + endforeach() + elseif( ${basename}_LIBRARY_RELEASE ) + set( ${basename}_LIBRARY ${${basename}_LIBRARY_RELEASE} ) + elseif( ${basename}_LIBRARY_DEBUG ) + set( ${basename}_LIBRARY ${${basename}_LIBRARY_DEBUG} ) + else() + set( ${basename}_LIBRARY "${basename}_LIBRARY-NOTFOUND") + endif() + + set( ${basename}_LIBRARIES "${${basename}_LIBRARY}" ) + + if( ${basename}_LIBRARY ) + set( ${basename}_FOUND TRUE ) + endif() + + mark_as_advanced( ${basename}_LIBRARY_RELEASE + ${basename}_LIBRARY_DEBUG + ) +endmacro() diff --git a/config-example.txt b/config-example.txt index d494736..b8c4a68 100644 --- a/config-example.txt +++ b/config-example.txt @@ -1,6 +1,49 @@ -# Use prior that dust follows modified double exponential disk, -# as described in Drimmel & Spergel (2001) +use-gaia = true + +verbosity = 1 +threads = 1 + +star-samplers = 10 + +# star-p-replacement = 0 + disk-prior = true +evidence-cut = 10 + +mean-RV = 3.3 + +log-Delta-EBV-min = -24. +log-Delta-EBV-max = -6. +sigma-log-Delta-EBV = 1.60 + +pct-smoothing-min = 0.15 +pct-smoothing-max = 0.50 + +discrete-los = true +save-surfs = true + +clouds = 0 +regions = 0 + +L_thin = 2600 +H_thin = 300 + +f_thick = 0.12 +L_thick = 3600 +H_thick = 900 + +f_halo = 0.0030 + +ext-file = PS1_2MASS_Extinction_APOGEE.dat +template-file = PS1_qz_2MASS_colors.dat +LF-file = PSMrLF.dat -# Lower halo fraction -f_halo = 0.0006 +dsc-n-temperatures = 4 +dsc-beta-spacing = 0.90 +dsc-n-swaps = 2000 +dsc-shift-weight-ladder-logarithmic = false +dsc-n-save = 100 +dsc-save-all-temperatures = true +dsc-p-badstar = 0.001 +dsc-central-steps-per-update = 20 +dsc-neighbor-steps-per-update = 5 \ No newline at end of file diff --git a/recompile-intel.sh b/recompile-intel.sh deleted file mode 100755 index cbd681f..0000000 --- a/recompile-intel.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh - -# Recompile bayestar -rm cmake_install.cmake -rm CMakeCache.txt -rm -R CMakeFiles/ -cmake . -DCMAKE_CXX_COMPILER=icpc -DCMAKE_C_COMPILER=icc -make -j diff --git a/recompile-profile-gen.sh b/recompile-profile-gen.sh deleted file mode 100755 index 4332cbe..0000000 --- a/recompile-profile-gen.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/sh - -# Recompile bayestar to generate profiling information -rm cmake_install.cmake -rm CMakeCache.txt -rm -R CMakeFiles/ -rm -R profiling/* -cmake . -DCMAKE_CXX_COMPILER=g++ -DCMAKE_C_COMPILER=gcc -DPROFILING_GEN=true -make -j diff --git a/recompile-profile-use.sh b/recompile-profile-use.sh deleted file mode 100755 index 4a22add..0000000 --- a/recompile-profile-use.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/sh - -# Recompile bayestar using profiling information -rm CMakeCache.txt -cmake . -DCMAKE_CXX_COMPILER=g++ -DCMAKE_C_COMPILER=gcc -DPROFILING_USE=true -make -j diff --git a/recompile.sh b/recompile.sh index 986ca49..effa408 100755 --- a/recompile.sh +++ b/recompile.sh @@ -1,8 +1,31 @@ #!/bin/sh +# Profiling options +prof_input=${1:-0} +prof_gen="FALSE" +prof_use="FALSE" +if [[ ${prof_input} -eq 1 ]]; then + prof_gen="TRUE" + prof_use="FALSE" +elif [[ ${prof_input} -eq 2 ]]; then + prof_gen="FALSE" + prof_use="TRUE" +fi + +echo "PROFILING_GEN=${prof_gen}" +echo "PROFILING_USE=${prof_use}" + # Recompile bayestar -rm cmake_install.cmake -rm CMakeCache.txt -rm -R CMakeFiles/ -cmake . -DCMAKE_CXX_COMPILER=g++ -DCMAKE_C_COMPILER=gcc -make -j + # -finline-functions \ + # -funroll-loops \ + # -floop-interchange \ + # -mavx \ + # -DBOOST_USE_STATIC_LIBS=ON \ + +cmake -S . -B . \ + -DCMAKE_BUILD_TYPE=RELEASE \ + -DPROFILING_GEN=${prof_gen} \ + -DPROFILING_USE=${prof_use} \ + . + +make VERBOSE=1 -j diff --git a/src/affine_sampler.h b/src/affine_sampler.h index 0772716..daa7141 100644 --- a/src/affine_sampler.h +++ b/src/affine_sampler.h @@ -38,6 +38,8 @@ #include #include +#include + #include #include @@ -262,7 +264,7 @@ class TParallelAffineSampler { void print_diagnostics(); void print_state() { for(unsigned int i=0; iprint_state(); } } void print_clusters() { for(unsigned int i=0; iprint_clusters(); } } - TAffineSampler* const get_sampler(unsigned int index) { assert(index < N_samplers); return sampler[index]; } + TAffineSampler* get_sampler(unsigned int index) { assert(index < N_samplers); return sampler[index]; } // Calculate the GR diagnostic on a transformed space void calc_GR_transformed(std::vector& GR, TTransformParamSpace* transf); @@ -586,24 +588,6 @@ void TAffineSampler::update_ensemble_cov() { } } - /*for(unsigned int j=0; j::step_affine(bool record_step) { // Update sampler j if(accept[j]) { + if(is_neg_inf_replacement(Y[j].pi)) { + #pragma omp critical (cout) + { + std::cerr << "!!! Accepted -infinity point! (affine step)" << std::endl; + } + } if(record_step) { chain.add_point(X[j].element, X[j].pi, (double)(X[j].weight)); @@ -1027,7 +1017,9 @@ void TAffineSampler::step_replacement(bool record_step, bool u } // Decide whether to accept or reject - if(alpha > 0.) { // Accept if probability of acceptance is greater than unity + if(is_neg_inf_replacement(Y[j].pi)) { + accept[j] = false; + } else if(alpha > 0.) { // Accept if probability of acceptance is greater than unity accept[j] = true; } else { p = gsl_rng_uniform(r); @@ -1060,6 +1052,13 @@ void TAffineSampler::step_replacement(bool record_step, bool u // Update sampler j if(accept[j]) { + if(is_neg_inf_replacement(Y[j].pi)) { + #pragma omp critical (cout) + { + std::cerr << "!!! Accepted -infinity point! (replacement step)" << std::endl; + } + } + if(record_step) { chain.add_point(X[j].element, X[j].pi, (double)(X[j].weight)); @@ -1136,6 +1135,13 @@ void TAffineSampler::step_MH(bool record_step) { // Update sampler j if(accept[j]) { + if(is_neg_inf_replacement(Y[j].pi)) { + #pragma omp critical (cout) + { + std::cerr << "!!! Accepted -infinity point! (MH step)" << std::endl; + } + } + if(record_step) { chain.add_point(X[j].element, X[j].pi, (double)(X[j].weight)); @@ -1786,6 +1792,7 @@ inline void seed_gsl_rng(gsl_rng **r) { clock_gettime(CLOCK_REALTIME, &t_seed); long unsigned int seed = 1e9*(long unsigned int)t_seed.tv_sec; seed += t_seed.tv_nsec; + seed ^= (long unsigned int)getpid(); *r = gsl_rng_alloc(gsl_rng_taus); gsl_rng_set(*r, seed); } @@ -1805,4 +1812,4 @@ struct TNullLogger { -#endif // _AFFINE_SAMPLER_H__ \ No newline at end of file +#endif // _AFFINE_SAMPLER_H__ diff --git a/src/bayestar_config.h b/src/bayestar_config.h new file mode 100644 index 0000000..c8210a7 --- /dev/null +++ b/src/bayestar_config.h @@ -0,0 +1,9 @@ +#ifndef _BAYESTAR_CONFIG_H__ +#define _BAYESTAR_CONFIG_H__ + + +#define DATADIR "/n/home12/czucker/projects/bayestar/data/" +#define GIT_BUILD_VERSION "" + + +#endif // _BAYESTAR_CONFIG_H__ diff --git a/src/binner.h b/src/binner.h index 19e62e0..6731a22 100644 --- a/src/binner.h +++ b/src/binner.h @@ -40,8 +40,8 @@ #include #include -#include -#include +#include +#include // Class for binning sparse data with minimal memory usage. This is especially useful // when the domain of the function being binned is of high dimension. In order to achieve diff --git a/src/bridging_sampler.cpp b/src/bridging_sampler.cpp new file mode 100644 index 0000000..962eeb0 --- /dev/null +++ b/src/bridging_sampler.cpp @@ -0,0 +1,950 @@ + +#include "bridging_sampler.h" + +#define LOGVERBOSE 0 + + +bridgesamp::BridgingSampler::BridgingSampler( + uint16_t n_dim, + uint16_t n_samples, + std::function&)> logp_node) + : n_dim(n_dim), n_samples(n_samples), + eval_node(logp_node), + r_dim(0,n_dim-1), r_samp(0,n_samples-1), + r_uniform(0., 1.) +{ + // Seed pseudo-random number generator + std::random_device rd; + r.seed(rd()); + + // Allocate memory to workspaces + _rand_state_dim_ws.resize(n_dim); + _gibbs_idx_samp_ws.resize(n_samples); + _gibbs_lnp_samp_ws.resize(n_samples); + _gibbs_state_dim_ws.resize(n_dim); + _transition_state_dim_ws.resize(n_dim); + _percolate_dim_ws.resize(n_dim); + + // Transition probabilities + b_prob.reserve(n_dim); + f_prob.reserve(n_dim); + + b_prob.push_back(0.5); + f_prob.push_back(0.); + for(int i=0; i&, // sample # in each dimension + std::vector& // holds log(p) of each state + )> f +) { + eval_conditional = f; +} + + +void bridgesamp::BridgingSampler::set_logp0(double _logp0) { + logp0 = _logp0; +} + + +uint16_t bridgesamp::BridgingSampler::get_n_dim() const { + return n_dim; +} + + +uint16_t bridgesamp::BridgingSampler::get_n_samples() const { + return n_samples; +} + + +const std::vector& bridgesamp::BridgingSampler::get_state() const { + return state->first; +} + + +double bridgesamp::BridgingSampler::get_logp() const { + return state->second.logp; +} + + +uint16_t bridgesamp::BridgingSampler::get_state_rank() const { + return state_rank; +} + + +void bridgesamp::BridgingSampler::randomize_state() { + #if LOGVERBOSE + std::cout << "Entering randomize_state()" << std::endl; + #endif + + // Choose random sample for each dimension + for(auto& s : _rand_state_dim_ws) { + s = r_samp(r); + } + + // Find node + auto it = node.find(_rand_state_dim_ws); + + // Create node if it doesn't exist + if(it == node.end()) { + #if LOGVERBOSE + std::cout << "Creating node"; + for(auto s : _rand_state_dim_ws) { + std::cout << " " << s; + } + std::cout << std::endl; + #endif + + double logp = eval_node(_rand_state_dim_ws); + it = node.insert( + std::make_pair( + _rand_state_dim_ws, + bridgesamp::Node{std::exp(logp), logp} + ) + ).first; + + percolate_up(it); + } + + // Update the state to point to this node + state = it; + state_rank = 0; // At 0th level in hierarchy + + #if LOGVERBOSE + std::cout << "Exiting randomize_state()" << std::endl; + #endif +} + + +void bridgesamp::BridgingSampler::_lazy_gibbs_inner( + std::vector& starting_state, + uint16_t dim) +{ + #if LOGVERBOSE + std::cout << "Entering _lazy_gibbs_inner()" << std::endl; + #endif + + #if LOGVERBOSE + std::cout << "Starting state:"; + for(auto s : starting_state) { + std::cout << " " << s; + } + std::cout << std::endl; + #endif + + // Find ln(p) of states that have already been explored + _gibbs_idx_samp_ws.clear(); // Will hold explored sample numbers + _gibbs_lnp_samp_ws.clear(); // Will hold corresponding ln(p) + + for(uint16_t s=0; ssecond.logp); + } + } + + uint16_t n_unexplored = n_samples - _gibbs_idx_samp_ws.size(); + + #if LOGVERBOSE + std::cout << n_unexplored << " of " << n_samples << " states unexplored." << std::endl; + #endif + + // Get maximum ln(p) of explored states + double lnp_max = *(std::max_element( + _gibbs_lnp_samp_ws.begin(), + _gibbs_lnp_samp_ws.end()) + ); + + // Find total ln(p) of explored states + double lnp_explored = 0.; + + for(auto lnp : _gibbs_lnp_samp_ws) { + lnp_explored += std::exp(lnp - lnp_max); + } + + lnp_explored = std::log(lnp_explored) + lnp_max; + + // Calculate total ln(p) of unexplored states + double ln_n_unexplored = std::log((double)(n_samples-_gibbs_idx_samp_ws.size())); + double lnp_unexplored = get_lnp0_of_rank(state_rank) + ln_n_unexplored; + + double lnp_tot = add_logs(lnp_unexplored, lnp_explored); + + #if LOGVERBOSE + std::cout << "p(explored) = " + << std::exp(lnp_explored-lnp_tot) << std::endl; + #endif + + // Decide whether to pick explored state + if(!n_unexplored || (std::log(r_uniform(r)) < lnp_explored-lnp_tot)) { + #if LOGVERBOSE + std::cout << "Picking explored state." << std::endl; + #endif + + // Pick explored state + for(auto& lnp : _gibbs_lnp_samp_ws) { + lnp = std::exp(lnp - lnp_max); + } + std::discrete_distribution d( + _gibbs_lnp_samp_ws.begin(), + _gibbs_lnp_samp_ws.end() + ); + + starting_state[dim] = _gibbs_idx_samp_ws[d(r)]; + state = node.find(starting_state); + + #if LOGVERBOSE + std::cout << "Picked explored state:"; + for(auto s : starting_state) { + std::cout << " " << s; + } + std::cout << std::endl; + #endif + } else { + #if LOGVERBOSE + std::cout << "Picking unexplored state." << std::endl; + #endif + + // Pick unexplored state at random + std::uniform_int_distribution d(0, n_unexplored-1); + uint16_t i_pick = d(r); + + #if LOGVERBOSE + std::cout << "Scanning for unexplored state #" + << i_pick << ":" << std::endl; + #endif + + // Scan through to find i_pick'th unexplored sample + int32_t idx = 0; + int32_t i_unexplored = -1; + auto it_explored = _gibbs_idx_samp_ws.begin(); + for(; i_unexplored != i_pick; idx++) { + #if LOGVERBOSE + std::cout << "- sample " << idx; + #endif + if((it_explored != _gibbs_idx_samp_ws.end()) && (*it_explored == idx)) { + #if LOGVERBOSE + std::cout << ": explored" << std::endl; + #endif + ++it_explored; + } else { + #if LOGVERBOSE + std::cout << ": unexplored" << std::endl; + #endif + ++i_unexplored; + } + } + + // Add the new state + starting_state[dim] = idx-1; + state = get_node(starting_state); + + #if LOGVERBOSE + std::cout << "Picked unexplored state:"; + for(auto s : starting_state) { + std::cout << " " << s; + } + std::cout << std::endl; + #endif + } + + #if LOGVERBOSE + std::cout << "Exiting _lazy_gibbs_inner()" << std::endl; + #endif +} + + +void bridgesamp::BridgingSampler::gibbs(uint16_t dim) { + #if LOGVERBOSE + std::cout << "Entering gibbs()" << std::endl; + #endif + + if(state_rank != 0) { + #if LOGVERBOSE + std::cout << "Can only take Gibbs step at zeroeth level in hierarchy." + << std::endl; + std::cout << "Exiting gibbs()" << std::endl; + #endif + return; + } + + // Copy current state into workspace + _gibbs_state_dim_ws.clear(); + std::copy( + state->first.begin(), + state->first.end(), + std::back_inserter(_gibbs_state_dim_ws) + ); + + #if LOGVERBOSE + std::cout << "Starting state:"; + for(auto s : _gibbs_state_dim_ws) { + std::cout << " " << s; + } + std::cout << std::endl; + #endif + + // Find out which nodes have been explored, and which not + _gibbs_idx_samp_ws.clear(); // Will hold samples corresponding to unexplored nodes + + NodeMap::iterator it; + + if(eval_conditional) { + #if LOGVERBOSE + std::cout << "Using conditional probability function." << std::endl; + #endif + + for(int k=0; ksecond.logp); + } + } + + #if LOGVERBOSE + std::cout << _gibbs_idx_samp_ws.size() << " of " << n_samples + << "states unexplored." << std::endl; + #endif + + // Determine log(p) of unexplored states using conditional prob. function + _gibbs_lnp_samp_ws.resize(n_samples); // Will hold log(p) of each node + if(_gibbs_idx_samp_ws.size()) { + eval_conditional(dim, _gibbs_state_dim_ws, _gibbs_lnp_samp_ws); + } + + // Add nodes, and percolate log(p) upward + double logp; + for(auto s : _gibbs_idx_samp_ws) { + _gibbs_state_dim_ws[dim] = s; + logp = _gibbs_lnp_samp_ws[s]; + + it = node.insert( + std::make_pair( + _gibbs_state_dim_ws, + bridgesamp::Node{std::exp(logp), logp} + ) + ).first; + + // Propagate change in log(p) upward + percolate_up(it); + } + } else { + #if LOGVERBOSE + std::cout << "No conditional probability function set." << std::endl; + #endif + + _gibbs_lnp_samp_ws.clear(); + + for(int k=0; ksecond.logp); + } + } + + // Get maximum log(p), and transform log(p) to p/p_max. + double logp_max = *std::max(_gibbs_lnp_samp_ws.begin(), _gibbs_lnp_samp_ws.end()); + for(auto& p : _gibbs_lnp_samp_ws) { + p = std::exp(p - logp_max); + } + + #if LOGVERBOSE + std::cout << "log(p_max) = " << logp_max << std::endl; + #endif + + std::discrete_distribution d( + _gibbs_lnp_samp_ws.begin(), + _gibbs_lnp_samp_ws.end()); + _gibbs_state_dim_ws[dim] = d(r); + + #if LOGVERBOSE + std::cout << "Chose sample #" << _gibbs_state_dim_ws[dim] << std::endl; + #endif + + state = get_node(_gibbs_state_dim_ws); + + // TODO: Bulk percolate-up function? + + #if LOGVERBOSE + std::cout << "Exiting gibbs()" << std::endl; + #endif +} + + +void bridgesamp::BridgingSampler::lazy_gibbs(uint16_t dim) { + #if LOGVERBOSE + std::cout << "Entering lazy_gibbs()" << std::endl; + #endif + + if(state->first[dim] == n_samples) { + #if LOGVERBOSE + std::cout << "Cannot take Gibbs step in empty dimension." << std::endl; + std::cout << "Exiting lazy_gibbs()" << std::endl; + #endif + return; + } + + // Copy current state into workspace + _gibbs_state_dim_ws.clear(); + std::copy( + state->first.begin(), + state->first.end(), + std::back_inserter(_gibbs_state_dim_ws) + ); + + _lazy_gibbs_inner(_gibbs_state_dim_ws, dim); + + #if LOGVERBOSE + std::cout << "Exiting lazy_gibbs()" << std::endl; + #endif +} + + +void bridgesamp::BridgingSampler::lazy_gibbs_choose_dim() { + #if LOGVERBOSE + std::cout << "Entering lazy_gibbs_choose_dim()" << std::endl; + #endif + + if(state_rank == n_dim) { + #if LOGVERBOSE + std::cout << "Cannot take a Gibbs step at the top level of the hierarchy." + << std::endl; + std::cout << "Exiting lazy_gibbs_choose_dim()" << std::endl; + #endif + return; + } + + // Choose which dimension to step in + std::uniform_int_distribution d(0, n_dim-state_rank-1); + uint16_t i_pick = d(r); + + #if LOGVERBOSE + std::cout << "Chose non-empty dimension #" << i_pick << std::endl; + #endif + + int32_t i_nonempty = -1; + uint16_t dim = 0; + for(auto it=state->first.begin(); i_nonempty != i_pick; ++it, dim++) { + if(*it != n_samples) { + i_nonempty++; + } + } + + #if LOGVERBOSE + std::cout << " -> dim = " << dim << std::endl; + #endif + + if(state_rank == 0) { + gibbs(dim); + } else { + lazy_gibbs(dim); + } + + #if LOGVERBOSE + std::cout << "Exiting lazy_gibbs_choose_dim()" << std::endl; + #endif +} + + +bridgesamp::NodeMap::const_iterator bridgesamp::BridgingSampler::cbegin() const { + return node.cbegin(); +} + + +bridgesamp::NodeMap::const_iterator bridgesamp::BridgingSampler::cend() const { + return node.cend(); +} + + +uint16_t bridgesamp::BridgingSampler::get_n_empty( + const std::vector& samp) +{ + uint16_t n_empty = 0; + for(auto s : samp) { + if(s == n_samples) { + n_empty++; + } + } + return n_empty; +} + + +double bridgesamp::BridgingSampler::get_lnp0_of_rank(uint16_t rank) { + return logp0 + rank * log_n_samples; +} + + +bridgesamp::NodeMap::iterator bridgesamp::BridgingSampler::get_node( + const std::vector& samp) +{ + #if LOGVERBOSE + std::cout << "Entering get_node()" << std::endl; + #endif + + // Find node + auto it = node.find(samp); + + // Get rank of node + uint16_t n_empty = get_n_empty(samp); + #if LOGVERBOSE + std::cout << "# empty: " << n_empty << std::endl; + #endif + + // Create node if it doesn't exist + if(it == node.end()) { + #if LOGVERBOSE + std::cout << "Creating node"; + for(auto s : samp) { + std::cout << " " << s; + } + std::cout << std::endl; + #endif + + // Calculate probability of new node + double logp; + if(n_empty == 0) { + // Evaluate rank-0 nodes exactly + logp = eval_node(samp); + #if LOGVERBOSE + std::cout << "Evaluated log(p) exactly: " << logp << std::endl; + #endif + + // Insert the node, and get iterator to it + it = node.insert( + std::make_pair(samp, bridgesamp::Node{std::exp(logp), logp}) + ).first; + + // Propagate change in log(p) upward + percolate_up(it); + } else { + // For higher-rank nodes, assume constant probability for + // all rank-0 child nodes. Probability = const * (# children), + // where # of children = (# of samples)^rank. + //logp = logp0 + n_empty * log_n_samples; + logp = get_lnp0_of_rank(n_empty); + #if LOGVERBOSE + std::cout << "Set log(p) to default: " << logp << std::endl; + #endif + + // Insert the node, and get iterator to it + it = node.insert( + std::make_pair(samp, bridgesamp::Node{std::exp(logp), logp}) + ).first; + } + } + + #if LOGVERBOSE + std::cout << "Exiting get_node()" << std::endl; + #endif + + return it; +} + + +double bridgesamp::add_logs(double loga, double logb) { + // Numerically stable way to add and , where their logarithms + // are taken as input, and log(a+b) is given as output. + if(loga > logb) { + return loga + std::log(1. + std::exp(logb-loga)); + } else { + return logb + std::log(1. + std::exp(loga-logb)); + } +} + + +double bridgesamp::subtract_logs(double loga, double logb) { + // Numerically stable way to subtract from , where their logarithms + // are taken as input, and log(a-b) is given as output. If b>a, then + // returns -infinity. + if(loga > logb) { + return loga + std::log(1. - std::exp(logb-loga)); + } else { + return -std::numeric_limits::infinity(); + } +} + + +void bridgesamp::BridgingSampler::transition_backward() { + #if LOGVERBOSE + std::cout << "Entering transition_backward()" << std::endl; + #endif + + #if LOGVERBOSE + std::cout << "Starting state:"; + for(auto s : state->first) { + std::cout << " " << s; + } + std::cout << std::endl; + #endif + + if(state_rank == n_dim) { + #if LOGVERBOSE + std::cout << "Already at highest level in hierarchy." << std::endl + << "Exiting transition_backward()" << std::endl; + #endif + return; + } + + // Find non-empty dimensions + get_nonempty_dims(state, _transition_state_dim_ws); + uint16_t n_nonempty = _transition_state_dim_ws.size(); + #if LOGVERBOSE + std::cout << n_nonempty << " non-empty dimensions" << std::endl; + #endif + + // Choose a dimension to blank + std::uniform_int_distribution d(0, n_nonempty-1); + uint16_t idx = _transition_state_dim_ws[d(r)]; + + #if LOGVERBOSE + std::cout << "Blanking dimension " << idx << std::endl; + #endif + + // Copy current state into workspace + _transition_state_dim_ws.clear(); + std::copy( + state->first.begin(), + state->first.end(), + std::back_inserter(_transition_state_dim_ws) + ); + + // Blank the chosen dimension and transition + _transition_state_dim_ws[idx] = n_samples; + state = get_node(_transition_state_dim_ws); + state_rank++; + + #if LOGVERBOSE + std::cout << "New state:"; + for(auto s : state->first) { + std::cout << " " << s; + } + std::cout << std::endl; + #endif + + #if LOGVERBOSE + std::cout << "Exiting transition_backward()" << std::endl; + #endif +} + + +void bridgesamp::BridgingSampler::transition_forward() { + #if LOGVERBOSE + std::cout << "Entering transition_forward()" << std::endl; + #endif + + #if LOGVERBOSE + std::cout << "Starting state:"; + for(auto s : state->first) { + std::cout << " " << s; + } + std::cout << std::endl; + #endif + + if(state_rank == 0) { + #if LOGVERBOSE + std::cout << "Already at lowest level in hierarchy." << std::endl + << "Exiting transition_forward()" << std::endl; + #endif + return; + } + + // Find empty dimensions + get_empty_dims(state, _transition_state_dim_ws); + uint16_t n_empty = _transition_state_dim_ws.size(); + #if LOGVERBOSE + std::cout << n_empty << " empty dimensions" << std::endl; + #endif + + // Choose a dimension to fill + std::uniform_int_distribution d(0, n_empty-1); + uint16_t idx = _transition_state_dim_ws[d(r)]; + + #if LOGVERBOSE + std::cout << "Filling dimension " << idx << std::endl; + #endif + + // Copy current state into workspace + _transition_state_dim_ws.clear(); + std::copy( + state->first.begin(), + state->first.end(), + std::back_inserter(_transition_state_dim_ws) + ); + + // Fill the chosen dimension with zero + _transition_state_dim_ws[idx] = 0; + state_rank--; + + // Take a Gibbs step + _lazy_gibbs_inner(_transition_state_dim_ws, idx); + + #if LOGVERBOSE + std::cout << "New state:"; + for(auto s : state->first) { + std::cout << " " << s; + } + std::cout << std::endl; + #endif + + #if LOGVERBOSE + std::cout << "Exiting transition_forward()" << std::endl; + #endif +} + + +void bridgesamp::BridgingSampler::percolate_up(const NodeMap::iterator& n) { + #if LOGVERBOSE + std::cout << "Entering percolate_up()" << std::endl; + #endif + + #if LOGVERBOSE + std::cout << "Starting from state:"; + for(auto s : n->first) { + std::cout << " " << s; + } + std::cout << std::endl; + #endif + + // Find non-empty dimensions + get_nonempty_dims(n, _percolate_dim_ws); + #if LOGVERBOSE + std::cout << _percolate_dim_ws.size() + << " non-empty dimensions" << std::endl; + #endif + + // Determine change in probability to propagate + double dlogp; // log(|dp|) + bool positive; // True if change is positive + if(n->second.logp >= logp0) { + dlogp = subtract_logs(n->second.logp, logp0); + positive = true; + } else { + dlogp = subtract_logs(logp0, n->second.logp); + positive = false; + } + + #if LOGVERBOSE + std::cout << "Change in probability:" << std::endl + << " dp = " << (positive ? "+" : "-") + << std::exp(dlogp) << std::endl + << " log(|dp|) = " << dlogp << " (" + << (positive ? "+" : "-") + << ")" << std::endl; + #endif + + // Loop through higher ranks in hierarchy + std::vector idx; + std::vector node_key; + idx.reserve(n_dim); + node_key.reserve(n_dim); + + for(int rank=1; rank<=_percolate_dim_ws.size(); rank++) { + // Blank out every combination of entries, obtaining + // keys to all parent nodes + CombinationGenerator cgen(_percolate_dim_ws.size(), rank); + while(cgen.next(idx)) { + #if LOGVERBOSE + std::cout << "Blanking dimensions:"; + for(auto i : idx) { + std::cout << " " << i; + } + std::cout << std::endl; + #endif + + // Copy original key into node_key + node_key.clear(); + std::copy( + n->first.begin(), + n->first.end(), + std::back_inserter(node_key) + ); + // Blank selected dimensions + for(auto i : idx) { + node_key[i] = n_samples; + } + #if LOGVERBOSE + std::cout << "Percolate to ="; + for(auto i : node_key) { + std::cout << " " << i; + } + std::cout << std::endl; + #endif + + auto it = get_node(node_key); // Iterator to parent node + + // Update probability of parent node + if(positive) { + it->second.logp = add_logs(it->second.logp, dlogp); + } else { + it->second.logp = subtract_logs(it->second.logp, dlogp); + } + } + } + + #if LOGVERBOSE + std::cout << "Exiting percolate_up()" << std::endl; + #endif +} + + +double bridgesamp::BridgingSampler::n_children(uint16_t order) { + return pow((double)(n_samples+1), (double)order); +} + + +void bridgesamp::BridgingSampler::get_nonempty_dims( + const NodeMap::iterator& n, + std::vector& dims_out) +{ + dims_out.clear(); + dims_out.reserve(n_dim); + + for(int i=0; ifirst[i] != n_samples) { + dims_out.push_back(i); + } + } +} + + +void bridgesamp::BridgingSampler::get_empty_dims( + const NodeMap::iterator& n, + std::vector& dims_out) +{ + dims_out.clear(); + dims_out.reserve(n_dim); + + for(int i=0; ifirst[i] == n_samples) { + dims_out.push_back(i); + } + } +} + + +double bridgesamp::BridgingSampler::fill_factor() const { + uint64_t n_obj = node.size(); + double n_obj_max = std::pow((double)n_samples+1., (double)n_dim); + + return (double)n_obj / n_obj_max; +} + + + +/* + * Combination generator - cycles through combinations (n choose r) + */ + +bridgesamp::CombinationGenerator::CombinationGenerator( + unsigned int n, unsigned int r) + : r(r), n(n), mask(n, false), finished(false) +{ + assert(n >= r); + std::fill(mask.end()-r, mask.end(), true); +} + + +void bridgesamp::CombinationGenerator::reset() { + std::fill(mask.begin(), mask.end()-r-1, false); + std::fill(mask.end()-r, mask.end(), true); + finished = false; +} + + +bool bridgesamp::CombinationGenerator::next(std::vector& out_idx) { + if(finished) { return false; } + + out_idx.resize(r); + //assert(out_idx.size() >= r); + + unsigned int k = 0; + for(unsigned int i=0; i& vec) const +{ + std::size_t seed = vec.size(); + for(auto& i : vec) { + seed ^= i + 0x9e3779b9 + (seed << 6) + (seed >> 2); + } + return seed; +} + diff --git a/src/bridging_sampler.h b/src/bridging_sampler.h new file mode 100644 index 0000000..899f31c --- /dev/null +++ b/src/bridging_sampler.h @@ -0,0 +1,196 @@ + +#ifndef __BRIDGING_SAMPLER_H__ +#define __BRIDGING_SAMPLER_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + +namespace bridgesamp { + + +class VectorHasher { + // Hashing function for vectors, required to use them as + // keys in an unordered_map. Taken from HolKann's + // StackOverflow answer: . +public: + std::size_t operator()(const std::vector& vec) const; +}; + + +struct Node { + // An individual state in the combinatorial space. Only need + // to store p and log(p), since the nodes will be stored in a + // map, with the state as the key. + double p, logp; +}; + + +// An unordered_map that maps state vectors -> (p, log(p)) +typedef std::unordered_map, Node, VectorHasher> NodeMap; + + +class BridgingSampler { +private: + uint16_t n_dim; // # of integers to define a state + uint16_t n_samples; // # of samples per dimension + + NodeMap node; // All visited nodes + NodeMap::iterator state; // Points to current node + uint16_t state_rank; // Rank of current state + + // Function that returns log(p) of node + std::function&)> eval_node; + + // Function that returns log(p) of several nodes that differ only in + // one dimension + std::function&, // sample # in each dimension + std::vector& // holds log(p) of each state + )> eval_conditional; + + double p0, logp0; // Assumed value of p (or log(p)) for unexplored nodes + double log_n_samples; + + // Sampling parameters + std::vector b_prob; // Probability of backward transition at each rank + std::vector f_prob; // Probability of forward transition at each rank + + // Random numbers + std::mt19937 r; + std::uniform_int_distribution r_dim; // Draw a random dimension + std::uniform_int_distribution r_samp; // Draw a random sample + std::uniform_real_distribution r_uniform; // Draw from U(0,1) + + // Workspaces + // - Worspaces ending in _dim_ws have capacity equal to n_dim + // - " " " _samp_ws " " " " n_samples + // Each workspace is named according to the member function that uses it + std::vector _rand_state_dim_ws; + std::vector _gibbs_idx_samp_ws; + std::vector _gibbs_lnp_samp_ws; + std::vector _gibbs_state_dim_ws; + std::vector _transition_state_dim_ws; + std::vector _percolate_dim_ws; + + // Navigation + //std::map, Node>::iterator up( + // std::map, Node>::iterator s, + // int + + // Returns an iterator to the node specified by the given sample numbers + NodeMap::iterator get_node(const std::vector& samp); + + // # of children of node of given order + double n_children(uint16_t order); + + // # of dimensions that are empty in key + uint16_t get_n_empty(const std::vector& samp); + + // Sampling routines + void percolate_up(const NodeMap::iterator& n); + + void _lazy_gibbs_inner(std::vector& starting_state, + uint16_t dim); + + // Get dimensions which are empty + void get_empty_dims(const NodeMap::iterator& n, + std::vector& dims_out); + + // Get dimensions which are set (non-empty) + void get_nonempty_dims(const NodeMap::iterator& n, + std::vector& dims_out); + + double get_lnp0_of_rank(uint16_t rank); + +public: + BridgingSampler(uint16_t n_dim, + uint16_t n_samples, + std::function&)> logp_node); + + void step(); // Choose and execute a step type + + void randomize_state(); // Jump to randomly chosen base state + + // Take a Gibbs step in the specified dimension + void gibbs(uint16_t dim); + + // Take a Gibbs step in the specified dimension, without evaluating + // unexplored states. + void lazy_gibbs(uint16_t dim); + + // Take a Gibbs step, choosing the dimension randomly + void lazy_gibbs_choose_dim(); + + // Transition to a randomly selected state one level up in the hierarchy + void transition_backward(); + + // Transition to a randomly selected state one level down in the hierarchy + void transition_forward(); + + // Set conditional probability function, to be used in Gibbs steps + void set_conditional_prob( + std::function&, // sample # in each dimension + std::vector& // holds log(p) of each state + )> f + ); + + void set_logp0(double _logp0); + + // Statistics + double fill_factor() const; // Fraction of nodes explored + + // Getters + NodeMap::const_iterator cbegin() const; + NodeMap::const_iterator cend() const; + + uint16_t get_n_dim() const; + uint16_t get_n_samples() const; + + const std::vector& get_state() const; + double get_logp() const; + uint16_t get_state_rank() const; // Get current level in hierarchy +}; + + +class CombinationGenerator { + // Cycles through combinations of elements. Generates + // n choose r combinations. +public: + // n choose r + CombinationGenerator(unsigned int n, unsigned int r); + + // Set to the next combination. Returns false + // if the final combination has already been reached. + bool next(std::vector& out_idx); + + // Reset the combination generator to the beginning + void reset(); + +private: + std::vector mask; // True for indices that will be selected + unsigned int n, r; + bool finished; // True if last combination has been reached +}; + + +// Misc functions +double add_logs(double loga, double logb); +double subtract_logs(double loga, double logb); + + +} + +#endif // __BRIDGING_SAMPLER_H__ diff --git a/src/chain.cpp b/src/chain.cpp index 4a83b0e..1f10b54 100644 --- a/src/chain.cpp +++ b/src/chain.cpp @@ -14,7 +14,7 @@ TChain::TChain(unsigned int _N, unsigned int _capacity) length = 0; total_weight = 0; set_capacity(_capacity); - + // Initialize min/max coordinates x_min.reserve(N); x_max.reserve(N); @@ -31,6 +31,7 @@ TChain::TChain(const TChain& c) stats = c.stats; x = c.x; L = c.L; + p = c.p; w = c.w; total_weight = c.total_weight; N = c.N; @@ -52,7 +53,11 @@ TChain::TChain(std::string filename, bool reserve_extra) TChain::~TChain() {} -void TChain::add_point(double* element, double L_i, double w_i) { +void TChain::add_point(const double *const element, + double L_i, + double p_i, + double w_i) +{ stats(element, (unsigned int)w_i); for(unsigned int i=0; i x_max[i]) { x_max[i] = element[i]; } } L.push_back(L_i); + p.push_back(p_i); w.push_back(w_i); total_weight += w_i; length += 1; } +void TChain::add_point(const double *const element, + double L_i, + double w_i) +{ + add_point(element, L_i, 0., w_i); // Use dummy value for prior +} + void TChain::clear() { x.clear(); L.clear(); + p.clear(); w.clear(); stats.clear(); total_weight = 0; length = 0; - + // Reset min/max coordinates for(unsigned int i=0; i &x) const { } unsigned int TChain::get_index_of_best() const { - double L_max = L[0]; + double pi_max = L[0] + p[0]; unsigned int i_max = 0; + double pi_tmp; for(unsigned int i=1; i L_max) { - L_max = L[i]; + pi_tmp = L[i] + p[i]; + if(pi_tmp > pi_max) { + pi_max = pi_tmp; i_max = i; } } @@ -138,50 +167,73 @@ unsigned int TChain::get_index_of_best() const { } -double TChain::append(const TChain& chain, bool reweight, bool use_peak, double nsigma_max, double nsigma_peak, double chain_frac, double threshold) { - assert(chain.N == N); // Make sure the two chains have the same dimensionality - +double TChain::append(const TChain& chain, + bool reweight, + bool use_peak, + double nsigma_max, + double nsigma_peak, + double chain_frac, + double threshold) +{ + // Make sure the two chains have the same dimensionality + assert(chain.N == N); + // Weight each chain according to Bayesian evidence, if requested double a1 = 1.; double a2 = 1.; double lnZ = 0.; if(reweight) { - double lnZ1 = chain.get_ln_Z_harmonic(use_peak, nsigma_max, nsigma_peak, chain_frac); - double lnZ2 = get_ln_Z_harmonic(use_peak, nsigma_max, nsigma_peak, chain_frac); - + double lnZ1 = chain.get_ln_Z_harmonic( + use_peak, + nsigma_max, + nsigma_peak, + chain_frac + ); + double lnZ2 = get_ln_Z_harmonic( + use_peak, + nsigma_max, + nsigma_peak, + chain_frac + ); + if(lnZ2 > lnZ1) { a2 = exp(lnZ1 - lnZ2) * total_weight / chain.total_weight; - /*if(isnan(a2)) { + /*if(std::isnan(a2)) { std::cout << std::endl; std::cout << "NaN Error: a2 = " << a2 << std::endl; std::cout << "ln(Z1) = " << lnZ1 << std::endl; std::cout << "ln(Z2) = " << lnZ2 << std::endl; std::cout << "total_weight = " << total_weight << std::endl; - std::cout << "chain.total_weight = " << chain.total_weight << std::endl; + std::cout << "chain.total_weight = " << chain.total_weight + << std::endl; std::cout << std::endl; }*/ } else { a1 = exp(lnZ2 - lnZ1) * chain.total_weight / total_weight; - /*if(isnan(a1)) { + /*if(std::isnan(a1)) { std::cout << std::endl; std::cout << "NaN Error: a1 = " << a1 << std::endl; std::cout << "ln(Z1) = " << lnZ1 << std::endl; std::cout << "ln(Z2) = " << lnZ2 << std::endl; std::cout << "total_weight = " << total_weight << std::endl; - std::cout << "chain.total_weight = " << chain.total_weight << std::endl; + std::cout << "chain.total_weight = " << chain.total_weight + << std::endl; std::cout << std::endl; }*/ } - + lnZ = log(a1/(a1+a2) * exp(lnZ2) + a2/(a1+a2) * exp(lnZ1)); } - - if(reweight) { std::cout << "(a1, a2) = " << a1 << ", " << a2 << std::endl; } - + + if(reweight) { + std::cout << "(a1, a2) = " << a1 << ", " << a2 << std::endl; + } + // Append the last chain to this one if(reweight && (a1 < threshold)) { x = chain.x; L = chain.L; + p = chain.p; w = chain.w; length = chain.length; capacity = chain.capacity; @@ -192,28 +244,37 @@ double TChain::append(const TChain& chain, bool reweight, bool use_peak, double x_min[i] = chain.x_min[i]; } } else if(!(reweight && (a2 < threshold))) { - if(capacity < length + chain.length) { set_capacity(1.5*(length + chain.length)); } + if(capacity < length + chain.length) { + set_capacity(1.5*(length + chain.length)); + } std::vector::iterator w_end_old = w.end(); x.insert(x.end(), chain.x.begin(), chain.x.end()); L.insert(L.end(), chain.L.begin(), chain.L.end()); + p.insert(p.end(), chain.p.begin(), chain.p.end()); w.insert(w.end(), chain.w.begin(), chain.w.end()); - + if(reweight) { std::vector::iterator w_end = w.end(); - for(std::vector::iterator it = w.begin(); it != w_end_old; ++it) { + for(std::vector::iterator it = w.begin(); + it != w_end_old; + ++it) + { *it *= a1; } - for(std::vector::iterator it = w_end_old; it != w_end; ++it) { + for(std::vector::iterator it = w_end_old; + it != w_end; + ++it) + { *it *= a2; } } - + stats *= a1; stats += a2 * chain.stats; length += chain.length; total_weight *= a1; total_weight += a2 * chain.total_weight; - + // Update min/max coordinates for(unsigned int i=0; i x_max[i]) { x_max[i] = chain.x_max[i]; } @@ -224,7 +285,7 @@ double TChain::append(const TChain& chain, bool reweight, bool use_peak, double //for(unsigned int i=0; i sorted_indices; sorted_indices.reserve(length); unsigned int filt_length = 0; for(unsigned int i=0; i inside the prior volume - double sum_invL = 0.; - double tmp_invL; + std::partial_sort( + sorted_indices.begin(), + sorted_indices.begin() + npoints, + sorted_indices.end() + ); + + // Determine <1/(L*p)> inside the prior volume + double sum_inv_pi = 0.; + double tmp_inv_pi; double nsigma = sqrt(sorted_indices[npoints-1].dist2); unsigned int tmp_index = sorted_indices[0].index;; double L_0 = L[tmp_index]; + double p_0 = p[tmp_index]; //std::cout << "index_0 = " << sorted_indices[0].index << std::endl; for(unsigned int i=0; i nsigma_max * nsigma_max) { @@ -314,56 +393,71 @@ double TChain::get_ln_Z_harmonic(bool use_peak, double nsigma_max, double nsigma break; } tmp_index = sorted_indices[i].index; - tmp_invL = w[tmp_index] / exp(L[tmp_index] - L_0); + tmp_inv_pi = w[tmp_index] + * exp(L_0 - L[tmp_index] + p_0 - p[tmp_index]); //std::cout << w[tmp_index] << ", " << L[tmp_index] << std::endl; - //if(isnan(tmp_invL)) { - // std::cout << "\t\tL, L_0 = " << L[tmp_index] << ", " << L_0 << std::endl; + //if(std::isnan(tmp_invL)) { + // std::cout << "\t\tL, L_0 = " << L[tmp_index] << ", " << L_0 + // << std::endl; //} - if((tmp_invL + sum_invL > 1.e100) && (i != 0)) { + if((tmp_inv_pi + sum_inv_pi > 1.e100) && (i != 0)) { nsigma = sqrt(sorted_indices[i-1].dist2); break; } - sum_invL += tmp_invL; + sum_inv_pi += tmp_inv_pi; } - + // Determine the volume normalization (the prior volume) - double V = sqrt(detSigma) * 2. * pow(SQRTPI * nsigma, (double)N) / (double)(N) / gsl_sf_gamma((double)(N)/2.); - + double V = sqrt(detSigma) + * 2. * pow(SQRTPI * nsigma, (double)N) + / (double)(N) + / gsl_sf_gamma((double)(N)/2.); + // Return an estimate of ln(Z) - double lnZ = log(V) - log(sum_invL) + log(total_weight) + L_0; - - if(isnan(lnZ)) { + double lnZ = log(V) - log(sum_inv_pi) + log(total_weight) + L_0 + p_0; + + if(std::isnan(lnZ)) { std::cout << std::endl; std::cout << "NaN Error! lnZ = " << lnZ << std::endl; - std::cout << "\tsum_invL = e^(" << -L_0 << ") * " << sum_invL << " = " << exp(-L_0) * sum_invL << std::endl; + std::cout << "\tsum_invL = e^(" + << -L_0-p_0 << ") * " << sum_inv_pi + << " = " << exp(-L_0-p_0) * sum_inv_pi + << std::endl; std::cout << "\tV = " << V << std::endl; - std::cout << "\ttotal_weight = " << total_weight << std::endl; + std::cout << "\ttotal_weight = " << total_weight + << std::endl; std::cout << std::endl; } else if(is_inf_replacement(lnZ)) { std::cout << std::endl; std::cout << "inf Error! lnZ = " << lnZ << std::endl; - std::cout << "\tsum_invL = e^(" << -L_0 << ") * " << sum_invL << " = " << exp(-L_0) * sum_invL << std::endl; + std::cout << "\tsum_inv_pi = e^(" << -L_0-p_0 << ") * " + << sum_inv_pi << " = " + << exp(-L_0-p_0) * sum_inv_pi << std::endl; std::cout << "\tV = " << V << std::endl; - std::cout << "\ttotal_weight = " << total_weight << std::endl; + std::cout << "\ttotal_weight = " << total_weight + << std::endl; std::cout << "\tnsigma = " << nsigma << std::endl; std::cout << "\tIndex\tDist^2:" << std::endl; for(unsigned int i=0; i<10; i++) { - std::cout << sorted_indices[i].index << "\t\t" << sorted_indices[i].dist2 << std::endl; + std::cout << sorted_indices[i].index << "\t\t" + << sorted_indices[i].dist2 << std::endl; std::cout << " "; const double *tmp_x = get_element(sorted_indices[i].index); - for(unsigned int k=0; k bins; uint64_t index; @@ -390,7 +484,7 @@ void TChain::density_peak(double* const peak, double nsigma) const { for(unsigned int k=0; k::iterator it_end = bins.end(); double w_max = neg_inf_replacement; @@ -400,7 +494,7 @@ void TChain::density_peak(double* const peak, double nsigma) const { index = it->first; } } - + // Convert the index to a coordinate uint64_t coord_index; for(unsigned int i=0; isize2 == N); assert(inv_cov->size1 == N); assert(inv_cov->size2 == N);*/ - + // Choose random point in chain as starting point gsl_rng *r; seed_gsl_rng(&r); - + long unsigned int index_tmp = gsl_rng_uniform_int(r, length); const double *x_tmp = get_element(index_tmp); for(unsigned int i=0; i file = H5Utils::openFile(fname); + if(!file) { return false; } + /* try { file->unlink(group_name); @@ -482,17 +576,14 @@ bool TChain::save(std::string fname, std::string group_name, size_t index, // pass } */ - - H5::Group *group = H5Utils::openGroup(file, group_name); - if(group == NULL) { - delete file; - return false; - } - + + std::unique_ptr group = H5Utils::openGroup(*file, group_name); + if(!group) { return false; } + /* * Attributes */ - + // Datatype H5::CompType att_type(sizeof(TChainAttribute)); hid_t tid = H5Tcopy(H5T_C_S1); @@ -501,47 +592,47 @@ bool TChain::save(std::string fname, std::string group_name, size_t index, //att_type.insertMember("total_weight", HOFFSET(TChainAttribute, total_weight), H5::PredType::NATIVE_FLOAT); //att_type.insertMember("ndim", HOFFSET(TChainAttribute, ndim), H5::PredType::NATIVE_UINT64); //att_type.insertMember("length", HOFFSET(TChainAttribute, length), H5::PredType::NATIVE_UINT64); - + // Dataspace int att_rank = 1; hsize_t att_dim = 1; H5::DataSpace att_space(att_rank, &att_dim); - + // Dataset //H5::Attribute att = group->createAttribute("parameter names", att_type, att_space); - + TChainAttribute att_data; att_data.dim_name = new char[dim_name.size()+1]; std::strcpy(att_data.dim_name, dim_name.c_str()); //att_data.total_weight = total_weight; //att_data.ndim = N; //att_data.length = length; - + //att.write(att_type, &att_data); delete[] att_data.dim_name; - + //int att_rank = 1; //hsize_t att_dim = 1; - + H5::DataType conv_dtype = H5::PredType::NATIVE_UCHAR; H5::DataSpace conv_dspace(att_rank, &att_dim); //H5::Attribute conv_att = H5Utils::openAttribute(group, "converged", conv_dtype, conv_dspace); //conv_att.write(conv_dtype, &converged); - + H5::DataType lnZ_dtype = H5::PredType::NATIVE_FLOAT; H5::DataSpace lnZ_dspace(att_rank, &att_dim); //H5::Attribute lnZ_att = H5Utils::openAttribute(group, "ln Z", lnZ_dtype, lnZ_dspace); //lnZ_att.write(lnZ_dtype, &lnZ); - + // Creation property list to be used for all three datasets H5::DSetCreatPropList plist; //plist.setDeflate(compression); // gzip compression level float fillvalue = 0; plist.setFillValue(H5::PredType::NATIVE_FLOAT, &fillvalue); - + H5D_layout_t layout = H5D_COMPACT; plist.setLayout(layout); - + /* * Choose subsample of points in chain */ @@ -560,9 +651,9 @@ bool TChain::save(std::string fname, std::string group_name, size_t index, } unrolled_idx += (size_t)(*it); } - + assert(chain_idx == length); - + gsl_rng *r; seed_gsl_rng(&r); subsample_idx = new size_t[tot_weight_tmp]; @@ -570,12 +661,12 @@ bool TChain::save(std::string fname, std::string group_name, size_t index, subsample_idx[i] = el_idx[gsl_rng_uniform_int(r, tot_weight_tmp)]; } } - - + + /* * Coordinates */ - + // Dataspace hsize_t dim; if(subsample > 0) { @@ -592,14 +683,14 @@ bool TChain::save(std::string fname, std::string group_name, size_t index, // plist.setChunk(rank, &chunk); //} H5::DataSpace x_dspace(rank, &(coord_dim[0])); - + // Dataset //std::stringstream x_dset_path; //x_dset_path << group_name << "/chain/coords"; std::stringstream coordname; coordname << "coords " << index; H5::DataSet* x_dataset = new H5::DataSet(group->createDataSet(coordname.str(), H5::PredType::NATIVE_FLOAT, x_dspace, plist)); - + // Write float *buf = new float[N*dim]; if(subsample > 0) { @@ -614,24 +705,24 @@ bool TChain::save(std::string fname, std::string group_name, size_t index, for(size_t i=0; iwrite(buf, H5::PredType::NATIVE_FLOAT); - - + + /* * Weights */ - + // Dataspace if(subsample <= 0) { dim = w.size(); - + rank = 1; H5::DataSpace w_dspace(rank, &dim); - + // Dataset //std::stringstream w_dset_path; //w_dset_path << group_name << "/chain/weights"; H5::DataSet* w_dataset = new H5::DataSet(group->createDataSet("weights", H5::PredType::NATIVE_FLOAT, w_dspace, plist)); - + // Write if(subsample > 0) { for(size_t i=0; iwrite(buf, H5::PredType::NATIVE_FLOAT); - + delete w_dataset; } - + /* * Probability densities */ - + // Dataspace rank = 1; H5::DataSpace L_dspace(rank, &dim); - + // Dataset //std::stringstream L_dset_path; //L_dset_path << group_name << "/chain/probs"; std::stringstream lnpname; lnpname << "ln_p " << index; H5::DataSet* L_dataset = new H5::DataSet(group->createDataSet(lnpname.str(), H5::PredType::NATIVE_FLOAT, L_dspace, plist)); - + // Write if(subsample > 0) { for(size_t i=0; iwrite(buf, H5::PredType::NATIVE_FLOAT); - - + + if(subsample > 0) { delete[] el_idx; delete[] subsample_idx; } - + delete[] buf; - + delete x_dataset; delete L_dataset; - - delete group; - delete file; - + return true; } bool TChain::load(std::string filename, bool reserve_extra) { std::fstream in(filename.c_str(), std::ios::in | std::ios::binary); - + if(!in.good()) { return false; } - + in.read(reinterpret_cast(&N), sizeof(unsigned int)); in.read(reinterpret_cast(&length), sizeof(unsigned int)); in.read(reinterpret_cast(&capacity), sizeof(unsigned int)); in.read(reinterpret_cast(&total_weight), sizeof(double)); - + if(!reserve_extra) { capacity = length; } - + x.reserve(N*capacity); L.reserve(capacity); w.reserve(capacity); - + x.resize(length); L.resize(length); w.resize(length); - + in.read(reinterpret_cast(&(x[0])), N * length * sizeof(double)); in.read(reinterpret_cast(&(L[0])), length * sizeof(double)); in.read(reinterpret_cast(&(w[0])), length * sizeof(double)); - + if(in.fail()) { in.close(); return false; } - + std::streampos read_offset = in.tellg(); in.close(); - + bool stats_success = stats.read_binary(filename, read_offset); - + return stats_success; } void TChain::get_image(cv::Mat& mat, const TRect& grid, unsigned int dim1, unsigned int dim2, - bool norm, double sigma1, double sigma2, double nsigma) const { + bool norm, double sigma1, double sigma2, double nsigma, bool sigma_pix_units) const { assert((dim1 >= 0) && (dim1 < N) && (dim2 >= 0) && (dim2 < N) && (dim1 != dim2)); - - mat = cv::Mat::zeros(grid.N_bins[0], grid.N_bins[1], CV_64F); - + + mat = cv::Mat::zeros(grid.N_bins[0], grid.N_bins[1], CV_FLOATING_TYPE); + //std::cout << grid.N_bins[0] << " " << grid.N_bins[1] << std::endl; - + unsigned int i1, i2; for(size_t i=0; i(i1, i2) += w[i]; + mat.at(i1, i2) += w[i]; //std::cerr << mat.at(i1, i2) << std::endl; } } - + if(norm) { mat /= total_weight; } - + if((sigma1 >= 0.) && (sigma2 >= 0.)) { - double s1 = sigma1 / grid.dx[0]; - double s2 = sigma2 / grid.dx[1]; - + double s1, s2; + if(sigma_pix_units) { // sigma1 and sigma2 are in units of pixels + s1 = sigma1; + s2 = sigma2; + } else { // sigma1 and sigma2 are in parameter units + s1 = sigma1 / grid.dx[0]; + s2 = sigma2 / grid.dx[1]; + } + //std::cout << std::endl; //std::cout << dim1 << " " << dim2 << std::endl; //std::cout << "dx = " << sigma1 << " / " << grid.dx[0] << " = " << s1 << std::endl; //std::cout << "dy = " << sigma2 << " / " << grid.dx[1] << " = " << s2 << std::endl; //std::cout << std::endl; - + int w1 = 2 * ceil(nsigma*s1) + 1; int w2 = 2 * ceil(nsigma*s2) + 1; - + cv::GaussianBlur(mat, mat, cv::Size(w2,w1), s2, s1, cv::BORDER_REPLICATE); } - + // Convert to float - mat.convertTo(mat, CV_32F); + mat.convertTo(mat, CV_FLOATING_TYPE); } @@ -771,7 +865,9 @@ void TChain::get_image(cv::Mat& mat, const TRect& grid, unsigned int dim1, unsig TImgWriteBuffer::TImgWriteBuffer(const TRect& rect, unsigned int nReserved) : rect_(rect), buf(NULL), nReserved_(0), length_(0) { + std::cerr << "rect_.N_bins = (" << rect_.N_bins[0] << ", " << rect_.N_bins[1] << ")" << std::endl; reserve(nReserved); + std::cerr << "Reserved memory for TImgWriteBuffer." << std::endl; } @@ -780,14 +876,19 @@ TImgWriteBuffer::~TImgWriteBuffer() { } void TImgWriteBuffer::reserve(unsigned int nReserved) { - assert(nReserved > nReserved_); + assert(nReserved >= nReserved_); float *buf_new = new float[rect_.N_bins[0] * rect_.N_bins[1] * nReserved]; if(buf != NULL) { + std::cerr << "Reserving: memcpy() ..." << std::endl; memcpy(buf_new, buf, sizeof(float) * rect_.N_bins[0] * rect_.N_bins[1] * length_); + std::cerr << "Reserving: memcpy() complete." << std::endl + << "Reserving: delete[] buf ..." << std::endl; delete[] buf; + std::cerr << "Reserving: Deleted buf." << std::endl; } buf = buf_new; nReserved_ = nReserved; + std::cerr << "Done reserving ..." << std::endl; } class ImageDimensionException: public std::exception { @@ -799,29 +900,34 @@ class ImageDimensionException: public std::exception { void TImgWriteBuffer::add(const cv::Mat& img) { // Make sure the image is of the correct dimensions if((img.rows != rect_.N_bins[0]) || (img.cols != rect_.N_bins[1])) { + std::cerr << "Image dimensions: (" << img.rows << ", " + << img.cols << ")" << std::endl; + std::cerr << "Buffer dimensions: (" << rect_.N_bins[0] << ", " + << rect_.N_bins[1] << ")" << std::endl; + throw imgDimException; } - + // Make sure buffer is long enough if(length_ >= nReserved_) { reserve(1.5 * (length_ + 1)); std::cout << "reserving for images" << std::endl; } - + float *const imgBuf = &(buf[rect_.N_bins[0] * rect_.N_bins[1] * length_]); for(size_t j=0; j(j,k); + imgBuf[rect_.N_bins[1]*j + k] = img.at(j,k); } } - + length_++; } void TImgWriteBuffer::write(const std::string& fname, const std::string& group, const std::string& img) { - H5::H5File* h5file = H5Utils::openFile(fname); - H5::Group* h5group = H5Utils::openGroup(h5file, group); - + std::unique_ptr h5file = H5Utils::openFile(fname); + std::unique_ptr h5group = H5Utils::openGroup(*h5file, group); + // Dataset properties: optimized for reading/writing entire buffer at once int rank = 3; hsize_t dim[3] = {length_, rect_.N_bins[0], rect_.N_bins[1]}; @@ -833,46 +939,51 @@ void TImgWriteBuffer::write(const std::string& fname, const std::string& group, } H5::DataSpace dspace(rank, &(dim[0])); H5::DSetCreatPropList plist; - plist.setDeflate(9); // gzip compression level + plist.setDeflate(3); // gzip compression level plist.setChunk(rank, &(chunk_dim[0])); float fillvalue = 0; plist.setFillValue(H5::PredType::NATIVE_FLOAT, &fillvalue); - + H5::DataSet* dataset = new H5::DataSet(h5group->createDataSet(img, H5::PredType::NATIVE_FLOAT, dspace, plist)); dataset->write(buf, H5::PredType::NATIVE_FLOAT); - + /* * Attributes */ - + hsize_t att_dim = 2; H5::DataSpace att_dspace(1, &att_dim); - + H5::PredType att_dtype = H5::PredType::NATIVE_UINT32; H5::Attribute att_N = dataset->createAttribute("nPix", att_dtype, att_dspace); att_N.write(att_dtype, &(rect_.N_bins)); - + att_dtype = H5::PredType::NATIVE_DOUBLE; H5::Attribute att_min = dataset->createAttribute("min", att_dtype, att_dspace); att_min.write(att_dtype, &(rect_.min)); - + att_dtype = H5::PredType::NATIVE_DOUBLE; H5::Attribute att_max = dataset->createAttribute("max", att_dtype, att_dspace); att_max.write(att_dtype, &(rect_.max)); - + delete dataset; - delete h5group; - delete h5file; } - /* * TChainWriteBuffer member functions */ -TChainWriteBuffer::TChainWriteBuffer(unsigned int nDim, unsigned int nSamples, unsigned int nReserved) - : buf(NULL), nDim_(nDim+1), nSamples_(nSamples), nReserved_(0), length_(0), samplePos(nSamples, 0) +TChainWriteBuffer::TChainWriteBuffer( + unsigned int nDim, + unsigned int nSamples, + unsigned int nReserved) + : buf(NULL), + nDim_(nDim+2), + nSamples_(nSamples), + nReserved_(0), + length_(0), + samplePos(nSamples, 0) { reserve(nReserved); seed_gsl_rng(&r); @@ -884,10 +995,14 @@ TChainWriteBuffer::~TChainWriteBuffer() { } void TChainWriteBuffer::reserve(unsigned int nReserved) { - assert(nReserved > nReserved_); + assert(nReserved >= nReserved_); float *buf_new = new float[nDim_ * (nSamples_+2) * nReserved]; if(buf != NULL) { - memcpy(buf_new, buf, sizeof(float) * nDim_ * (nSamples_+2) * length_); + memcpy( + buf_new, + buf, + sizeof(float) * nDim_ * (nSamples_+2) * length_ + ); delete[] buf; } buf = buf_new; @@ -895,99 +1010,156 @@ void TChainWriteBuffer::reserve(unsigned int nReserved) { nReserved_ = nReserved; } -void TChainWriteBuffer::add(const TChain& chain, bool converged, double lnZ, double * GR) { +void TChainWriteBuffer::add(const TChain& chain, + bool converged, + double lnZ, + double * GR, + bool subsample) +{ // Make sure buffer is long enough if(length_ >= nReserved_) { reserve(1.5 * (length_ + 1)); std::cout << "reserving" << std::endl; } - + // Store metadata - TChainMetadata meta = {converged, lnZ}; + TChainMetadata meta = {converged, (float)lnZ}; metadata.push_back(meta); - - // Choose which points in chain to sample - double totalWeight = chain.get_total_weight(); - for(unsigned int i=0; i::quiet_NaN(); } - k++; } } - assert(k == nSamples_); - + // Copy best point into buffer - i = chain.get_index_of_best(); + unsigned int i = chain.get_index_of_best(); chainElement = chain.get_element(i); - buf[startIdx + nDim_] = chain.get_L(i); - for(size_t n = 1; n < nDim_; n++) { - buf[startIdx + nDim_ + n] = chainElement[n-1]; + buf[start_idx + nDim_] = chain.get_L(i); + buf[start_idx + nDim_ + 1] = chain.get_p(i); + for(size_t n = 2; n < nDim_; n++) { + buf[start_idx + nDim_ + n] = chainElement[n-2]; } - + // Copy the Gelman-Rubin diagnostic into the buffer - buf[startIdx] = std::numeric_limits::quiet_NaN(); + buf[start_idx] = std::numeric_limits::quiet_NaN(); + buf[start_idx+1] = std::numeric_limits::quiet_NaN(); if(GR == NULL) { - for(size_t n = 1; n < nDim_; n++) { - buf[startIdx + n] = std::numeric_limits::quiet_NaN(); + for(size_t n = 2; n < nDim_; n++) { + buf[start_idx + n] = std::numeric_limits::quiet_NaN(); } } else { //std::cout << "Writing G-R ..." << std::endl; - for(size_t n = 1; n < nDim_; n++) { + for(size_t n = 2; n < nDim_; n++) { //std::cout << n << std::endl; - buf[startIdx + n] = GR[n-1]; + buf[start_idx + n] = GR[n-2]; } } - + //std::cout << "Done." << std::endl; - + length_++; } -void TChainWriteBuffer::write(const std::string& fname, const std::string& group, const std::string& chain, const std::string& meta) { - H5::H5File* h5file = H5Utils::openFile(fname); - H5::Group* h5group = H5Utils::openGroup(h5file, group); - +void TChainWriteBuffer::write( + const std::string& fname, + const std::string& group, + const std::string& chain, + const std::string& meta) +{ + std::unique_ptr h5file = H5Utils::openFile(fname); + std::unique_ptr h5group = H5Utils::openGroup(*h5file, group); + // Dataset properties: optimized for reading/writing entire buffer at once int rank = 3; hsize_t dim[3] = {length_, nSamples_+2, nDim_}; H5::DataSpace dspace(rank, &(dim[0])); H5::DSetCreatPropList plist; - plist.setDeflate(9); // gzip compression level + plist.setDeflate(3); // gzip compression level plist.setChunk(rank, &(dim[0])); float fillvalue = 0; plist.setFillValue(H5::PredType::NATIVE_FLOAT, &fillvalue); - + H5::DataSet* dataset = NULL; try { - dataset = new H5::DataSet(h5group->createDataSet(chain, H5::PredType::NATIVE_FLOAT, dspace, plist)); + dataset = new H5::DataSet( + h5group->createDataSet( + chain, + H5::PredType::NATIVE_FLOAT, + dspace, + plist + ) + ); } catch(H5::GroupIException &group_exception) { - std::cerr << "Could not create dataset for chain." << std::endl; - std::cerr << "Dataset '" << group << "/" << chain << "' most likely already exists." << std::endl; + std::cerr << "Could not create dataset for chain." + << std::endl; + std::cerr << "Dataset '" << group << "/" + << chain << "' most likely already exists." + << std::endl; throw; } - + dataset->write(buf, H5::PredType::NATIVE_FLOAT); - + if(meta == "") { // Store metadata as attributes bool *converged = new bool[length_]; float *lnZ = new float[length_]; @@ -995,8 +1167,9 @@ void TChainWriteBuffer::write(const std::string& fname, const std::string& group converged[i] = metadata[i].converged; lnZ[i] = metadata[i].lnZ; } - - // Allow large attributes to be stored in dense storage, versus compact (which has 64 kB limit) + + // Allow large attributes to be stored in dense storage, + // versus compact (which has 64 kB limit) //if(length_ > 5) { // hid_t dID = dataset->getCreatePlist().getId(); // herr_t res = H5Pset_attr_phase_change(dID, 0, 0); @@ -1005,41 +1178,63 @@ void TChainWriteBuffer::write(const std::string& fname, const std::string& group // std::cerr << "Failed to specify dense storage." << std::endl; // } //} - + H5::DataSpace convSpace(1, &(dim[0])); - H5::Attribute convAtt = dataset->createAttribute("converged", H5::PredType::NATIVE_CHAR, convSpace); - convAtt.write(H5::PredType::NATIVE_CHAR, reinterpret_cast(converged)); - + H5::Attribute convAtt = dataset->createAttribute( + "converged", + H5::PredType::NATIVE_CHAR, + convSpace + ); + convAtt.write(H5::PredType::NATIVE_CHAR, + reinterpret_cast(converged)); + H5::DataSpace lnZSpace(1, &(dim[0])); - H5::Attribute lnZAtt = dataset->createAttribute("ln(Z)", H5::PredType::NATIVE_FLOAT, lnZSpace); + H5::Attribute lnZAtt = dataset->createAttribute( + "ln(Z)", + H5::PredType::NATIVE_FLOAT, + lnZSpace + ); lnZAtt.write(H5::PredType::NATIVE_FLOAT, lnZ); - + delete[] converged; delete[] lnZ; } else { // Store metadata as separate dataset H5::CompType metaType(sizeof(TChainMetadata)); - metaType.insertMember("converged", HOFFSET(TChainMetadata, converged), H5::PredType::NATIVE_CHAR); - metaType.insertMember("ln(Z)", HOFFSET(TChainMetadata, lnZ), H5::PredType::NATIVE_FLOAT); - + metaType.insertMember( + "converged", + HOFFSET(TChainMetadata, converged), + H5::PredType::NATIVE_CHAR + ); + metaType.insertMember( + "ln(Z)", + HOFFSET(TChainMetadata, lnZ), + H5::PredType::NATIVE_FLOAT + ); + rank = 1; H5::DataSpace metaSpace(rank, &(dim[0])); H5::DSetCreatPropList metaProp; TChainMetadata emptyMetadata = {0, 0}; metaProp.setFillValue(metaType, &emptyMetadata); - metaProp.setDeflate(9); + metaProp.setDeflate(3); metaProp.setChunk(rank, &(dim[0])); - - H5::DataSet* metaDataset = new H5::DataSet(h5group->createDataSet(meta, metaType, metaSpace, metaProp)); + + H5::DataSet* metaDataset = new H5::DataSet( + h5group->createDataSet( + meta, + metaType, + metaSpace, + metaProp + ) + ); metaDataset->write(metadata.data(), metaType); - + delete metaDataset; metaDataset = NULL; } - + delete dataset; - delete h5group; - delete h5file; - + //std::cerr << "Cleaned up." << std::endl; } @@ -1070,17 +1265,56 @@ TRect::TRect(const TRect& rect) { TRect::~TRect() { } + bool TRect::get_index(double x1, double x2, unsigned int& i1, unsigned int& i2) const { if((x1 < min[0]) || (x1 >= max[0]) || (x2 < min[1]) || (x2 >= max[1])) { return false; } - + + i1 = (x1 - min[0]) / dx[0]; + i2 = (x2 - min[1]) / dx[1]; + + return true; +} + + +bool TRect::get_index(double x1, double x2, double& i1, double& i2) const { + if((x1 < min[0]) || (x1 >= max[0]) || (x2 < min[1]) || (x2 >= max[1])) { + return false; + } + i1 = (x1 - min[0]) / dx[0]; i2 = (x2 - min[1]) / dx[1]; - + return true; } + +bool TRect::get_interpolant(double x1, double x2, + unsigned int& i1, unsigned int& i2, + double& a1, double& a2) const { + // (x1, x2) must lie between centers of image pixels + // (cannot be on outer rim). + if((x1 < min[0] + 0.5*dx[0]) || (x1 >= max[0] - 0.5*dx[0]) || + (x2 < min[1] + 0.5*dx[1]) || (x2 >= max[1] - 0.5*dx[1])) { + return false; + } + + // Get lower pixel center + double i1_float = (x1 - min[0]) / dx[0] - 0.5; + double i2_float = (x2 - min[1]) / dx[1] - 0.5; + + i1 = floor(i1_float); + i2 = floor(i2_float); + + // Get interpolating weights + a1 = i1_float - i1; + a2 = i2_float - i2; + + return true; +} + + TRect& TRect::operator=(const TRect& rhs) { if(&rhs != this) { for(size_t i=0; i<2; i++) { @@ -1099,7 +1333,7 @@ TRect& TRect::operator=(const TRect& rhs) { * TGaussianMixture member functions */ -TGaussianMixture::TGaussianMixture(unsigned int _ndim, unsigned int _nclusters) +TGaussianMixture::TGaussianMixture(unsigned int _ndim, unsigned int _nclusters) : ndim(_ndim), nclusters(_nclusters) { w = new double[nclusters]; @@ -1157,11 +1391,11 @@ void TGaussianMixture::invert_covariance() { // Calculate the density of the mixture at a series of N points stored in x. // The result is stored in res. -// +// // Inputs: // x[N * ndim] points at which to evaluate the Gaussian density // N # of points -// +// // Output: // res[nclusters * N] Gaussian density at given points // @@ -1197,11 +1431,11 @@ double TGaussianMixture::density(const double *x) { void TGaussianMixture::expectation_maximization(const double *x, const double *w_n, unsigned int N, unsigned int iterations) { double *p_kn = new double[nclusters*N]; - + // Determine total weight double sum_w = 0.; for(unsigned int n=0; nkij', p_kn, w, Delta, Delta) //cov = np.einsum('kij,k->kij', cov, 1./np.sum(p_kn, axis=1)) } - + // Find the vector sqrt_cov s.t. sqrt_cov sqrt_cov^T = cov. for(unsigned int k=0; k 9)) { std::cerr << "! Invalid gzip compression level: " << compression << std::endl; return false; } - + H5::Exception::dontPrint(); - - H5::H5File *file = H5Utils::openFile(fname); - if(file == NULL) { return false; } - - H5::Group *group = H5Utils::openGroup(file, group_name); - if(group == NULL) { - delete file; - return false; - } - + + std::unique_ptr file = H5Utils::openFile(fname); + if(!file) { return false; } + + std::unique_ptr group = H5Utils::openGroup(*file, group_name); + if(!group) { return false; } + /* * Image Data */ - + // Creation property list H5::DSetCreatPropList plist; int rank = 2; @@ -1409,48 +1640,46 @@ bool save_mat_image(cv::Mat& img, TRect& rect, std::string fname, std::string gr plist.setFillValue(H5::PredType::NATIVE_FLOAT, &fillvalue); plist.setChunk(rank, &(dim[0])); H5::DataSpace dspace(rank, &(dim[0])); - + H5::DataSet* dataset; try { dataset = new H5::DataSet(group->createDataSet(dset_name, H5::PredType::NATIVE_FLOAT, dspace, plist)); } catch(H5::FileIException create_dset_err) { std::cerr << "Unable to create dataset '" << dset_name << "'." << std::endl; - delete group; - delete file; return false; } - + float *buf = new float[rect.N_bins[0]*rect.N_bins[1]]; for(size_t j=0; j(j,k); - /*float tmp = img.at(j,k); + buf[rect.N_bins[1]*j + k] = img.at(j,k); + /*float tmp = img.at(j,k); if(tmp > 0.) { std::cerr << j << ", " << k << " --> " << j + rect.N_bins[0]*k << " --> " << tmp << std::endl; }*/ } } dataset->write(buf, H5::PredType::NATIVE_FLOAT); - + /* * Attributes */ - + hsize_t att_dim = 2; H5::DataSpace att_dspace(1, &att_dim); - + H5::PredType att_dtype = H5::PredType::NATIVE_UINT32; H5::Attribute att_N = dataset->createAttribute("N_pix", att_dtype, att_dspace); att_N.write(att_dtype, &(rect.N_bins)); - + att_dtype = H5::PredType::NATIVE_DOUBLE; H5::Attribute att_min = dataset->createAttribute("min", att_dtype, att_dspace); att_min.write(att_dtype, &(rect.min)); - + att_dtype = H5::PredType::NATIVE_DOUBLE; H5::Attribute att_max = dataset->createAttribute("max", att_dtype, att_dspace); att_max.write(att_dtype, &(rect.max)); - + att_dim = 1; H5::StrType vls_type(0, H5T_VARIABLE); H5::DataSpace att_space_str(H5S_SCALAR); @@ -1458,16 +1687,14 @@ bool save_mat_image(cv::Mat& img, TRect& rect, std::string fname, std::string gr att_name_1.write(vls_type, dim1); H5::Attribute att_name_2 = dataset->createAttribute("dim_name_2", vls_type, att_space_str); att_name_2.write(vls_type, dim2); - + file->close(); - + delete[] buf; delete dataset; - delete group; - delete file; - + return true; - + } @@ -1494,26 +1721,26 @@ void Gelman_Rubin_diagnostic(const std::vector& chains, std::vector 1); const size_t ndim = chains[0]->get_ndim(); - + TStats **stats = new TStats*[n_chains]; - + for(size_t n=0; nget_ndim() == ndim); - + stats[n] = new TStats(ndim); TStats& stat = *(stats[n]); - + size_t n_points = chain->get_length(); - + for(size_t i=0; iget_element(i), (unsigned int)(chain->get_w(i))); } } - + R.resize(ndim); Gelman_Rubin_diagnostic(stats, n_chains, R.data(), ndim); - + for(size_t n=0; n& chains, std::vector& chains, std::vectorsize1; assert(N == A->size2); - + // Allocate workspaces if none are provided bool del_p = false; bool del_LU = false; if(p == NULL) { p = gsl_permutation_alloc(N); del_p = true; } if(LU == NULL) { LU = gsl_matrix_alloc(N, N); del_LU = true; } - + int s; int status = 1; int count = 0; while(status) { if(count > 5) { std::cerr << "! Error inverting matrix." << std::endl; abort(); } - + // Invert A using LU decomposition gsl_matrix_memcpy(LU, A); if(count != 0) { // If inversion fails the first time, add small constant to diagonal - gsl_matrix_add_diagonal(LU, pow10((double)count - 6.)); + gsl_matrix_add_diagonal(LU, exp10((double)count - 6.)); std::cerr << "Invert matrix: Added 10^" << count - 6 << " to diagonal." << std::endl; } gsl_linalg_LU_decomp(LU, p, &s); @@ -1559,17 +1786,17 @@ double invert_matrix(gsl_matrix* A, gsl_matrix* inv_A, gsl_permutation* p, gsl_m assert(N == inv_A->size2); status = gsl_linalg_LU_invert(LU, p, inv_A); } - + count++; } - + // Get the determinant of A double det_A = gsl_linalg_LU_det(LU, s); - + // Free workspaces if none were provided if(del_p) { gsl_permutation_free(p); } if(del_LU) { gsl_matrix_free(LU); } - + return det_A; } @@ -1578,12 +1805,12 @@ double invert_matrix(gsl_matrix* A, gsl_matrix* inv_A, gsl_permutation* p, gsl_m void sqrt_matrix(gsl_matrix* A, gsl_matrix* sqrt_A, gsl_eigen_symmv_workspace* esv, gsl_vector *eival, gsl_matrix *eivec, gsl_matrix* sqrt_eival) { size_t N = A->size1; assert(A->size2 == N); - + assert(sqrt_eival->size1 == N); assert(sqrt_eival->size2 == N); - + gsl_matrix_set_zero(sqrt_eival); - + if(sqrt_A == NULL) { sqrt_A = A; } else { @@ -1591,7 +1818,7 @@ void sqrt_matrix(gsl_matrix* A, gsl_matrix* sqrt_A, gsl_eigen_symmv_workspace* e assert(sqrt_A->size2 == N); gsl_matrix_memcpy(sqrt_A, A); } - + // Calculate the eigendecomposition of the covariance matrix gsl_eigen_symmv(sqrt_A, eival, eivec, esv); double tmp; @@ -1608,15 +1835,15 @@ void sqrt_matrix(gsl_matrix* A, gsl_matrix* sqrt_A, gsl_eigen_symmv_workspace* e // Same as above, but allocates and de-allocates worskspaces internally void sqrt_matrix(gsl_matrix* A, gsl_matrix* sqrt_A) { size_t N = A->size1; - + // Allocate workspaces gsl_eigen_symmv_workspace* esv = gsl_eigen_symmv_alloc(N); gsl_vector *eival = gsl_vector_alloc(N); gsl_matrix *eivec = gsl_matrix_alloc(N, N); gsl_matrix* sqrt_eival = gsl_matrix_alloc(N, N); - + sqrt_matrix(A, sqrt_A, esv, eival, eivec, sqrt_eival); - + // Free workspaces gsl_matrix_free(sqrt_eival); gsl_eigen_symmv_free(esv); diff --git a/src/chain.h b/src/chain.h index ce377d2..4155642 100644 --- a/src/chain.h +++ b/src/chain.h @@ -1,26 +1,26 @@ /* * chain.h - * + * * Defines class representing a Markov Chain, for use in MCMC routines. - * + * * This file is part of bayestar. * Copyright 2012 Gregory Green - * + * * Bayestar is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. - * + * */ #ifndef _CHAIN_H__ @@ -41,6 +41,8 @@ #include #include +#include + #include #include @@ -53,8 +55,8 @@ #include -#include -#include +#include +#include #include "definitions.h" #include "h5utils.h" @@ -81,7 +83,7 @@ struct TGaussianMixture { gsl_matrix **inv_cov; gsl_matrix **sqrt_cov; double *det_cov; - + // Workspaces gsl_permutation *p; gsl_matrix *LU; @@ -90,24 +92,24 @@ struct TGaussianMixture { gsl_matrix *eivec; gsl_matrix *sqrt_eival; gsl_rng *r; - + // Constructor / Destructor TGaussianMixture(unsigned int _ndim, unsigned int _nclusters); ~TGaussianMixture(); - + // Accessors gsl_matrix* get_cov(unsigned int k); double get_w(unsigned int k); double* get_mu(unsigned int k); void draw(double *x); void print(); - + // Mutators void invert_covariance(); - + void density(const double *x, unsigned int N, double *res); double density(const double *x); - + void expectation_maximization(const double *x, const double *w, unsigned int N, unsigned int iterations=10); }; @@ -118,13 +120,20 @@ class TRect { uint32_t N_bins[2]; double min[2]; double max[2]; - + TRect(double _min[2], double _max[2], uint32_t _N_bins[2]); TRect(const TRect& rect); ~TRect(); - - bool get_index(double x1, double x2, unsigned int &i1, unsigned int &i2) const; - + + bool get_index(double x1, double x2, + unsigned int &i1, unsigned int &i2) const; + bool get_index(double x1, double x2, + double& i1, double& i2) const; + + bool get_interpolant(double x1, double x2, + unsigned int& i1, unsigned int& i2, + double& a1, double& a2) const; + TRect& operator =(const TRect& rhs); }; @@ -137,13 +146,14 @@ class TChain { private: std::vector x; // Elements in chain. Each point takes up N contiguous slots in array std::vector L; // Likelihood of each point in chain + std::vector p; // Prior of each point in chain std::vector w; // Weight of each point in chain double total_weight; // Sum of the weights unsigned int N, length, capacity; // # of dimensions, length and capacity of chain - + std::vector x_min; std::vector x_max; - + struct TChainAttribute { char *dim_name; float total_weight; @@ -152,58 +162,115 @@ class TChain { public: TStats stats; // Keeps track of statistics of chain - + TChain(unsigned int _N, unsigned int _capacity); TChain(const TChain& c); TChain(std::string filename, bool reserve_extra=false); // Construct the chain from a file ~TChain(); - + // Mutators - void add_point(double* element, double L_i, double w_i); // Add a point to the end of the chain - void clear(); // Remove all the points from the chain - void set_capacity(unsigned int _capacity); // Set the capacity of the vectors used in the chain - double append(const TChain& chain, bool reweight=false, bool use_peak=true, double nsigma_max=1., - double nsigma_peak=0.1, double chain_frac=0.05, double threshold=1.e-5); // Append a second chain to this one + // Add a point to the end of the chain + void add_point(const double *const element, + double L_i, double w_i); + void add_point(const double *const element, + double L_i, double p_i, double w_i); + + // Remove all the points from the chain + void clear(); + + // Set the capacity of the vectors used in the chain + void set_capacity(unsigned int _capacity); + + // Append a second chain to this one + double append(const TChain& chain, + bool reweight=false, + bool use_peak=true, + double nsigma_max=1., + double nsigma_peak=0.1, + double chain_frac=0.05, + double threshold=1.e-5); + + void set_L(unsigned int i, double L_i); + void set_p(unsigned int i, double p_i); + // Accessors - unsigned int get_capacity() const; // Return the capacity of the vectors used in the chain - unsigned int get_length() const; // Return the number of unique points in the chain - double get_total_weight() const; // Return the sum of the weights in the chain - const double* get_element(unsigned int i) const; // Return the i-th point in the chain - void get_best(std::vector &x) const; // Return best point in chain + + // Return the capacity of the vectors used in the chain + unsigned int get_capacity() const; + + // Return the number of unique points in the chain + unsigned int get_length() const; + + // Return the sum of the weights in the chain + double get_total_weight() const; + + // Return the i-th point in the chain + const double* get_element(unsigned int i) const; + + // Return best point in chain + void get_best(std::vector &x) const; unsigned int get_index_of_best() const; - double get_L(unsigned int i) const; // Return the likelihood of the i-th point - double get_w(unsigned int i) const; // Return the weight of the i-th point + + // Return the likelihood of the i-th point + double get_L(unsigned int i) const; + + // Return the prior of the i-th point + double get_p(unsigned int i) const; + + // Return the weight of the i-th point + double get_w(unsigned int i) const; + + // Get # of dimensions in the parameter space unsigned int get_ndim() const; - + // Computations on chain - - // Estimate the Bayesian Evidence of the posterior using the bounded Harmonic Mean Approximation - double get_ln_Z_harmonic(bool use_peak=true, double nsigma_max=1., - double nsigma_peak=0.1, double chain_frac=0.1) const; - + + // Estimate the Bayesian Evidence of the posterior + // using the bounded Harmonic Mean Approximation + double get_ln_Z_harmonic(bool use_peak=true, + double nsigma_max=1., + double nsigma_peak=0.1, + double chain_frac=0.1) const; + // Estimate coordinates with peak density by binning void density_peak(double* const peak, double nsigma) const; - - // Find a point in space with high density by picking a random point, drawing an ellipsoid, - // taking the mean coordinate within the ellipsoid, and then iterating - void find_center(double* const center, gsl_matrix *const cov, gsl_matrix *const inv_cov, - double* det_cov, double dmax=1., unsigned int iterations=5) const; - - void fit_gaussian_mixture(TGaussianMixture *gm, unsigned int iterations=10); - + + // Find a point in space with high density by picking + // a random point, drawing an ellipsoid, taking the mean + // coordinate within the ellipsoid, and then iterating + void find_center(double* const center, + gsl_matrix *const cov, + gsl_matrix *const inv_cov, + double* det_cov, + double dmax=1., + unsigned int iterations=5) const; + + // Fit a Gaussian mixture model to the chain + void fit_gaussian_mixture(TGaussianMixture *gm, + unsigned int iterations=10); + // Return an image, optionally with smoothing void get_image(cv::Mat &mat, const TRect &grid, unsigned int dim1, unsigned int dim2, bool norm=true, - double sigma1=-1., double sigma2=-1., double nsigma=5.) const; - + double sigma1=-1., double sigma2=-1., double nsigma=5., + bool sigma_pix_units=false) const; + // File IO - // Save the chain to an HDF5 file - bool save(std::string fname, std::string group_name, size_t index, - std::string dim_name, int compression=1, int subsample=-1, - bool converged=true, float lnZ=std::numeric_limits::quiet_NaN()) const; - bool load(std::string filename, bool reserve_extra=false); // Load the chain from file + // Save the chain to an HDF5 file + bool save(std::string fname, + std::string group_name, + size_t index, + std::string dim_name, + int compression=1, + int subsample=-1, + bool converged=true, + float lnZ=std::numeric_limits::quiet_NaN()) const; + + // Load the chain from file + bool load(std::string filename, bool reserve_extra=false); + // Operators const double* operator [](unsigned int i); // Calls get_element void operator +=(const TChain& rhs); // Calls append @@ -217,33 +284,35 @@ class TChain { class TChainWriteBuffer { public: - TChainWriteBuffer(unsigned int nDim, unsigned int nSamples, unsigned int nReserved = 10); + TChainWriteBuffer(unsigned int nDim, + unsigned int nSamples, + unsigned int nReserved = 10); ~TChainWriteBuffer(); - + void add(const TChain &chain, bool converged = true, double lnZ = std::numeric_limits::quiet_NaN(), - double * GR = NULL - ); - + double * GR = NULL, + bool subsample = true); + void reserve(unsigned int nReserved); - + void write(const std::string& fname, const std::string& group, const std::string& chain, const std::string& meta=""); - + private: float *buf; unsigned int nDim_, nSamples_, nReserved_, length_; gsl_rng *r; std::vector samplePos; - + struct TChainMetadata { bool converged; float lnZ; }; - + std::vector metadata; - + }; /************************************************************************* @@ -254,13 +323,13 @@ class TImgWriteBuffer { public: TImgWriteBuffer(const TRect& rect, unsigned int nReserved = 10); ~TImgWriteBuffer(); - + void add(const cv::Mat& img); - + void reserve(unsigned int nReserved); - + void write(const std::string& fname, const std::string& group, const std::string& img); - + private: float *buf; unsigned int nReserved_, length_; @@ -268,7 +337,6 @@ class TImgWriteBuffer { }; - /************************************************************************* * Convergence diagnostics in transformed parameter space * (e.g. observable space) @@ -278,10 +346,10 @@ class TTransformParamSpace { public: TTransformParamSpace(unsigned int ndim); virtual ~TTransformParamSpace(); - + virtual void transform(const double *const x, double *const y); void operator()(const double *const x, double *const y); - + private: unsigned int _ndim; }; @@ -315,6 +383,7 @@ inline void seed_gsl_rng(gsl_rng **r) { clock_gettime(CLOCK_REALTIME, &t_seed); long unsigned int seed = 1e9*(long unsigned int)t_seed.tv_sec; seed += t_seed.tv_nsec; + seed ^= (long unsigned int)getpid(); *r = gsl_rng_alloc(gsl_rng_taus); gsl_rng_set(*r, seed); } @@ -335,4 +404,4 @@ void sqrt_matrix(gsl_matrix* A, gsl_matrix* sqrt_A=NULL); // Draw a normal varariate from a covariance matrix. The square-root of the covariance (as defined in sqrt_matrix) must be provided. void draw_from_cov(double* x, const gsl_matrix* sqrt_cov, unsigned int N, gsl_rng* r); -#endif // _CHAIN_H__ \ No newline at end of file +#endif // _CHAIN_H__ diff --git a/src/data.cpp b/src/data.cpp index 06d8cff..f25bed3 100644 --- a/src/data.cpp +++ b/src/data.cpp @@ -1,26 +1,26 @@ /* * data.cpp - * + * * Defines class for stellar data. - * + * * This file is part of bayestar. * Copyright 2012 Gregory Green - * + * * Bayestar is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. - * + * */ #include "data.h" @@ -42,13 +42,13 @@ TStellarData::TStellarData(const std::string& infile, std::string _pix_name, dou TStellarData::TStellarData(uint64_t _healpix_index, uint32_t _nside, bool _nested, double _l, double _b) { - healpix_index = _healpix_index; + healpix_index = _healpix_index; nside = _nside; nested = _nested; l = _l; b = _b; EBV = -1.; - + std::stringstream tmp_name; tmp_name << "pixel " << nside << "-" << healpix_index; pix_name = tmp_name.str(); @@ -60,28 +60,25 @@ bool TStellarData::save(const std::string& fname, const std::string& group, cons std::cerr << "! Invalid gzip compression level: " << compression << std::endl; return false; } - + hsize_t nstars = star.size(); if(nstars == 0) { std::cerr << "! No stars to write." << std::endl; return false; } - + H5::Exception::dontPrint(); - - H5::H5File *file = H5Utils::openFile(fname); - if(file == NULL) { return false; } - - H5::Group *gp = H5Utils::openGroup(file, group); - if(gp == NULL) { - delete file; - return false; - } - + + std::unique_ptr file = H5Utils::openFile(fname); + if(!file) { return false; } + + std::unique_ptr gp = H5Utils::openGroup(*file, group); + if(!gp) { return false; } + /* * Photometry */ - + // Datatype hsize_t nbands = NBANDS; H5::ArrayType f4arr(H5::PredType::NATIVE_FLOAT, 1, &nbands); @@ -90,30 +87,34 @@ bool TStellarData::save(const std::string& fname, const std::string& group, cons dtype.insertMember("obj_id", HOFFSET(TFileData, obj_id), H5::PredType::NATIVE_UINT64); dtype.insertMember("l", HOFFSET(TFileData, l), H5::PredType::NATIVE_DOUBLE); dtype.insertMember("b", HOFFSET(TFileData, b), H5::PredType::NATIVE_DOUBLE); + dtype.insertMember("pi", HOFFSET(TFileData, pi), H5::PredType::NATIVE_FLOAT); + dtype.insertMember("pi_err", HOFFSET(TFileData, pi_err), H5::PredType::NATIVE_FLOAT); dtype.insertMember("mag", HOFFSET(TFileData, mag), f4arr); dtype.insertMember("err", HOFFSET(TFileData, err), f4arr); dtype.insertMember("maglimit", HOFFSET(TFileData, maglimit), f4arr); dtype.insertMember("nDet", HOFFSET(TFileData, N_det), u4arr); dtype.insertMember("EBV", HOFFSET(TFileData, EBV), H5::PredType::NATIVE_FLOAT); - + // Dataspace hsize_t dim = nstars; H5::DataSpace dspace(1, &dim); - + // Property List H5::DSetCreatPropList plist; plist.setChunk(1, &nstars); plist.setDeflate(compression); - + // Dataset H5::DataSet dataset = gp->createDataSet(dset, dtype, dspace, plist); - + // Write dataset TFileData* data = new TFileData[nstars]; for(size_t i=0; iclose(); - + delete[] data; - delete gp; - delete file; - + return true; } @@ -168,15 +167,26 @@ void TStellarData::TMagnitudes::set(const TStellarData::TFileData& dat, double e obj_id = dat.obj_id; l = dat.l; b = dat.b; + pi = dat.pi; + pi_err = dat.pi_err; lnL_norm = 0.; for(unsigned int i=0; i file = H5Utils::openFile(fname); + if(!file) { return false; } + + std::unique_ptr gp = H5Utils::openGroup(*file, group); + if(!gp) { return false; } + H5::DataSet dataset = gp->openDataSet(dset); - + /* * Photometry */ - + // Datatype hsize_t nbands = NBANDS; H5::ArrayType f4arr(H5::PredType::NATIVE_FLOAT, 1, &nbands); @@ -207,70 +214,73 @@ bool TStellarData::load(const std::string& fname, const std::string& group, cons dtype.insertMember("obj_id", HOFFSET(TFileData, obj_id), H5::PredType::NATIVE_UINT64); dtype.insertMember("l", HOFFSET(TFileData, l), H5::PredType::NATIVE_DOUBLE); dtype.insertMember("b", HOFFSET(TFileData, b), H5::PredType::NATIVE_DOUBLE); + dtype.insertMember("pi", HOFFSET(TFileData, pi), H5::PredType::NATIVE_FLOAT); + dtype.insertMember("pi_err", HOFFSET(TFileData, pi_err), H5::PredType::NATIVE_FLOAT); dtype.insertMember("mag", HOFFSET(TFileData, mag), f4arr); dtype.insertMember("err", HOFFSET(TFileData, err), f4arr); dtype.insertMember("maglimit", HOFFSET(TFileData, maglimit), f4arr); dtype.insertMember("nDet", HOFFSET(TFileData, N_det), u4arr); dtype.insertMember("EBV", HOFFSET(TFileData, EBV), H5::PredType::NATIVE_FLOAT); - + // Dataspace hsize_t length; H5::DataSpace dataspace = dataset.getSpace(); dataspace.getSimpleExtentDims(&length); - + // Read in dataset TFileData* data_buf = new TFileData[length]; dataset.read(data_buf, dtype); //std::cerr << "# Read in dimensions." << std::endl; - + // Fix magnitude limits for(int n=0; n maglimit; for(hsize_t i=0; i 10.) && (tmp < 40.) && (!isnan(tmp))) { + + if((tmp > 10.) && (tmp < 40.) && (!std::isnan(tmp))) { maglimit.push_back(tmp); } } - + //std::sort(maglimit.begin(), maglimit.end()); if(maglimit.size() != 0) { maglim_replacement = percentile(maglimit, 95.); } - + // Replace missing magnitude limits with the 95th percentile magnitude limit for(hsize_t i=0; i 10.) && (tmp < 40.)) || isnan(tmp)) { + + if(!((tmp > 10.) && (tmp < 40.)) || std::isnan(tmp)) { //std::cout << i << ", " << n << ": " << tmp << std::endl; data_buf[i].maglimit[n] = maglim_replacement; } } } - + //int n_filtered = 0; //int n_M_dwarfs = 0; - + TMagnitudes mag_tmp; for(size_t i=0; i 20.) { M_dwarf = false; } else if(mag_tmp.m[1] - mag_tmp.m[2] - (A_r - A_i) / (A_g - A_r) * (mag_tmp.m[0] - mag_tmp.m[1]) < 0.) { @@ -300,55 +310,53 @@ bool TStellarData::load(const std::string& fname, const std::string& group, cons n_M_dwarfs++; } */ - + /*if(n_informative >= 4) { //&& (!M_dwarf)) { star.push_back(mag_tmp); } else { n_filtered++; }*/ } - + //std::cerr << "# of stars filtered: " << n_filtered << std::endl; //std::cerr << "# of M dwarfs: " << n_M_dwarfs << std::endl; - + /* * Attributes */ - + H5::Attribute att = dataset.openAttribute("healpix_index"); H5::DataType att_dtype = H5::PredType::NATIVE_UINT64; att.read(att_dtype, reinterpret_cast(&healpix_index)); - + att = dataset.openAttribute("nested"); att_dtype = H5::PredType::NATIVE_UCHAR; att.read(att_dtype, reinterpret_cast(&nested)); - + att = dataset.openAttribute("nside"); att_dtype = H5::PredType::NATIVE_UINT32; att.read(att_dtype, reinterpret_cast(&nside)); - + att = dataset.openAttribute("l"); att_dtype = H5::PredType::NATIVE_DOUBLE; att.read(att_dtype, reinterpret_cast(&l)); - + att = dataset.openAttribute("b"); att_dtype = H5::PredType::NATIVE_DOUBLE; att.read(att_dtype, reinterpret_cast(&b)); - + att = dataset.openAttribute("EBV"); att_dtype = H5::PredType::NATIVE_DOUBLE; att.read(att_dtype, reinterpret_cast(&EBV)); - + // TEST: Force l, b to anticenter //l = 180.; //b = 0.; - - if((EBV <= 0.) || (EBV > default_EBV) || isnan(EBV)) { EBV = default_EBV; } - + + if((EBV <= 0.) || (EBV > default_EBV) || std::isnan(EBV)) { EBV = default_EBV; } + delete[] data_buf; - delete gp; - delete file; - + return true; } @@ -361,11 +369,11 @@ TDraw1D::TDraw1D(func_ptr_t func, double _x_min, double _x_max, void* _params, u : x_of_P(NULL), r(NULL), params(_params) { assert(samples > 1); - + x_min = _x_min; x_max = _x_max; double dx = (x_max - x_min) / (double)(samples - 1); - + // Construct an interpolator for P(x) double fill = -1.; TMultiLinearInterp P_of_x(&x_min, &x_max, &samples, 1, fill); @@ -379,7 +387,7 @@ TDraw1D::TDraw1D(func_ptr_t func, double _x_min, double _x_max, void* _params, u } } double P_norm = P; - + // Invert the interpolator for get x(P) double P_min = 0.; double P_max = 1.; @@ -399,12 +407,12 @@ TDraw1D::TDraw1D(func_ptr_t func, double _x_min, double _x_max, void* _params, u break; } } - + x_of_P->set(&P, x); } P_tmp = 1.; x_of_P->set(&P_tmp, x_max); - + seed_gsl_rng(&r); } @@ -465,29 +473,29 @@ void draw_from_synth_model(size_t nstars, double RV, TGalacticLOSModel& gal_mode TStellarData& stellar_data, TExtinctionModel& ext_model, double (&mag_limit)[5]) { unsigned int samples = 1000; void* gal_model_ptr = static_cast(&gal_model); - + double DM_min = 0.; double DM_max = 25.; TDraw1D draw_DM(&log_dNdmu_draw, DM_min, DM_max, gal_model_ptr, samples, true); - + double logMass_min = -0.9; double logMass_max = 1.1; TDraw1D draw_logMass_disk(&disk_IMF_draw, logMass_min, logMass_max, gal_model_ptr, samples, false); TDraw1D draw_logMass_halo(&halo_IMF_draw, logMass_min, logMass_max, gal_model_ptr, samples, false); - + double tau_min = 1.e6; double tau_max = 13.e9; TDraw1D draw_tau_disk(&disk_SFR_draw, tau_min, tau_max, gal_model_ptr, samples, false); TDraw1D draw_tau_halo(&halo_SFR_draw, tau_min, tau_max, gal_model_ptr, samples, false); - + double FeH_min = -2.5; double FeH_max = 1.; TDraw1D draw_FeH_disk(&disk_FeH_draw, FeH_min, FeH_max, gal_model_ptr, samples, false); TDraw1D draw_FeH_halo(&halo_FeH_draw, FeH_min, FeH_max, gal_model_ptr, samples, false); - + stellar_data.clear(); gal_model.get_lb(stellar_data.l, stellar_data.b); - + gsl_rng *r; seed_gsl_rng(&r); double EBV, DM, logtau, logMass, FeH; @@ -505,10 +513,10 @@ void draw_from_synth_model(size_t nstars, double RV, TGalacticLOSModel& gal_mode while(!observed) { // Draw E(B-V) EBV = gsl_ran_chisq(r, 1.); - + // Draw DM DM = draw_DM(); - + // Draw stellar type f_halo = gal_model.f_halo(DM); halo = (gsl_rng_uniform(r) < f_halo); @@ -525,7 +533,7 @@ void draw_from_synth_model(size_t nstars, double RV, TGalacticLOSModel& gal_mode } in_lib = stellar_model.get_sed(logMass, logtau, FeH, sed); } - + // Generate magnitudes observed = true; unsigned int N_nonobs = 0; @@ -533,7 +541,7 @@ void draw_from_synth_model(size_t nstars, double RV, TGalacticLOSModel& gal_mode mag[k] = sed.absmag[k] + DM + EBV * ext_model.get_A(RV, k); err[k] = 0.02 + 0.1*exp(mag[i]-mag_limit[i]-1.5); mag[k] += gsl_ran_gaussian_ziggurat(r, err[k]); - + // Require detection in g band and 3 other bands if(mag[k] > mag_limit[k]) { N_nonobs++; @@ -544,7 +552,7 @@ void draw_from_synth_model(size_t nstars, double RV, TGalacticLOSModel& gal_mode } } } - + std::cout << (halo ? "halo" : "disk") << " "; std::cout << std::setw(9) << EBV << " "; std::cout << std::setw(9) << DM << " "; @@ -555,25 +563,25 @@ void draw_from_synth_model(size_t nstars, double RV, TGalacticLOSModel& gal_mode std::cout << std::setw(9) << mag[k] << " "; } std::cout << std::endl; - + TStellarData::TMagnitudes mag_tmp(mag, err); mag_tmp.obj_id = i; mag_tmp.l = stellar_data.l; mag_tmp.b = stellar_data.b; stellar_data.star.push_back(mag_tmp); - + } std::cout << std::endl; - + gsl_rng_free(r); - + /*std::vector filled; DM_of_P.get_filled(filled); for(std::vector::iterator it = filled.begin(); it != filled.end(); ++it) { std::cout << *it << std::endl; } */ - + } @@ -583,23 +591,23 @@ void draw_from_emp_model(size_t nstars, double RV, TGalacticLOSModel& gal_model, unsigned int samples = 1000; void* gal_model_ptr = static_cast(&gal_model); void* stellar_model_ptr = static_cast(&stellar_model); - + double DM_min = 0.; double DM_max = 25.; TDraw1D draw_DM(&log_dNdmu_draw, DM_min, DM_max, gal_model_ptr, samples, true); - + double FeH_min = -2.5; double FeH_max = 1.; TDraw1D draw_FeH_disk(&disk_FeH_draw, FeH_min, FeH_max, gal_model_ptr, samples, false); TDraw1D draw_FeH_halo(&halo_FeH_draw, FeH_min, FeH_max, gal_model_ptr, samples, false); - + double Mr_min = -1.; double Mr_max = mag_limit[1]; TDraw1D draw_Mr(&Mr_draw, Mr_min, Mr_max, stellar_model_ptr, samples, true); - + stellar_data.clear(); gal_model.get_lb(stellar_data.l, stellar_data.b); - + gsl_rng *r; seed_gsl_rng(&r); double EBV, DM, Mr, FeH; @@ -617,14 +625,14 @@ void draw_from_emp_model(size_t nstars, double RV, TGalacticLOSModel& gal_model, while(!observed) { // Draw DM DM = draw_DM(); - + // Draw E(B-V) //EBV = gsl_ran_chisq(r, 1.); - + EBV = 0.; //if(DM > 5.) { EBV += 0.05; } if(DM > 10.) { EBV += 2.5; } - + // Draw stellar type f_halo = gal_model.f_halo(DM); halo = (gsl_rng_uniform(r) < f_halo); @@ -638,7 +646,7 @@ void draw_from_emp_model(size_t nstars, double RV, TGalacticLOSModel& gal_model, Mr = draw_Mr(); in_lib = stellar_model.get_sed(Mr, FeH, sed); } - + // Generate magnitudes observed = true; unsigned int N_nonobs = 0; @@ -648,13 +656,13 @@ void draw_from_emp_model(size_t nstars, double RV, TGalacticLOSModel& gal_model, err[k] = 0.02 + 0.3*exp(mag[k]-mag_limit[k]); if(err[k] > 1.) { err[k] = 1.; } mag[k] += gsl_ran_gaussian_ziggurat(r, err[k]); - + // Require detection in g band and 3 other bands p_det = 0.5 - 0.5 * erf((mag[k] - mag_limit[k] + 0.5) / 0.25); if(gsl_rng_uniform(r) > p_det) { mag[k] = 0.; err[k] = 1.e10; - + N_nonobs++; if((k == 0) || N_nonobs > 1) { observed = false; @@ -663,7 +671,7 @@ void draw_from_emp_model(size_t nstars, double RV, TGalacticLOSModel& gal_model, } } } - + std::cout << std::setw(9) << i+1 << " "; std::cout << (halo ? "halo" : "disk") << " "; std::cout << std::setw(9) << EBV << " "; @@ -674,35 +682,35 @@ void draw_from_emp_model(size_t nstars, double RV, TGalacticLOSModel& gal_model, std::cout << std::setw(9) << mag[k] << " "; } std::cout << std::endl; - + TStellarData::TMagnitudes mag_tmp(mag, err); mag_tmp.obj_id = i; mag_tmp.l = stellar_data.l; mag_tmp.b = stellar_data.b; stellar_data.star.push_back(mag_tmp); - + } std::cout << std::endl; - + gsl_rng_free(r); - + /*std::vector filled; DM_of_P.get_filled(filled); for(std::vector::iterator it = filled.begin(); it != filled.end(); ++it) { std::cout << *it << std::endl; } */ - + } herr_t fetch_pixel_name(hid_t loc_id, const char *name, void *opdata) { std::vector *pix_name = reinterpret_cast*>(opdata); - + std::string group_name(name); //group_name << name; - + //std::string tmp_name; try { //group_name >> tmp_name; @@ -710,23 +718,51 @@ herr_t fetch_pixel_name(hid_t loc_id, const char *name, void *opdata) { } catch(...) { // pass } - + return 0; } -void get_input_pixels(std::string fname, std::vector &pix_name) { - H5::H5File *file = H5Utils::openFile(fname, H5Utils::READ); - - file->iterateElems("/photometry/", NULL, fetch_pixel_name, reinterpret_cast(&pix_name)); - - delete file; +void get_input_pixels( + std::string fname, + std::vector &pix_name, + const std::string &base +) { + std::unique_ptr file = H5Utils::openFile(fname, H5Utils::READ); + + file->iterateElems(base, NULL, fetch_pixel_name, reinterpret_cast(&pix_name)); +} + + +void get_pixel_props( + const std::string& fname, + const std::vector& pix_name, + std::vector& l, + std::vector& b, + std::vector& EBV, + std::vector& nside, + std::vector& healpix_index, + const std::string& base +) { + std::unique_ptr f = H5Utils::openFile(fname, H5Utils::READ); + + for(auto& name : pix_name) { + std::stringstream path; + path << base << "/" << name; + std::unique_ptr g = H5Utils::openGroup(*f, path.str(), H5Utils::READ); + if(!g) { std::cerr << "Could not load " << path.str() << " !" << std::endl; } + l.push_back(H5Utils::read_attribute(*g, "l")); + b.push_back(H5Utils::read_attribute(*g, "b")); + EBV.push_back(H5Utils::read_attribute(*g, "EBV")); + nside.push_back(H5Utils::read_attribute(*g, "nside")); + healpix_index.push_back(H5Utils::read_attribute(*g, "healpix_index")); + } } /************************************************************************* - * + * * Auxiliary Functions - * + * *************************************************************************/ #ifndef __SEED_GSL_RNG_ @@ -737,6 +773,7 @@ inline void seed_gsl_rng(gsl_rng **r) { clock_gettime(CLOCK_REALTIME, &t_seed); long unsigned int seed = 1e9*(long unsigned int)t_seed.tv_sec; seed += t_seed.tv_nsec; + seed ^= (long unsigned int)getpid(); *r = gsl_rng_alloc(gsl_rng_taus); gsl_rng_set(*r, seed); } diff --git a/src/data.h b/src/data.h index 4f42065..0c65198 100644 --- a/src/data.h +++ b/src/data.h @@ -40,6 +40,8 @@ //#define __STDC_LIMIT_MACROS #include +#include + #include #include @@ -54,20 +56,23 @@ void seed_gsl_rng(gsl_rng **r); struct TStellarData { struct TFileData { uint64_t obj_id; - double l, b; - float mag[NBANDS]; - float err[NBANDS]; - float maglimit[NBANDS]; - uint32_t N_det[NBANDS]; - float EBV; + double l, b; // Galactic (l, b), in deg + float pi, pi_err; // parallax, in milliarcseconds + float mag[NBANDS]; // Observed magnitudes, in mag + float err[NBANDS]; // Magnitude uncertainties, in mag + float maglimit[NBANDS]; // Limit magnitudes, in mag + uint32_t N_det[NBANDS]; // # of detections in each passband + float EBV; // E(B-V), in mag }; struct TMagnitudes { uint64_t obj_id; double l, b; + double pi, pi_err; double m[NBANDS]; double err[NBANDS]; double maglimit[NBANDS]; + double maglim_width[NBANDS]; unsigned int N_det[NBANDS]; double EBV; double lnL_norm; @@ -80,6 +85,7 @@ struct TStellarData { m[i] = _m[i]; err[i] = _err[i]; maglimit[i] = 23.; + maglim_width[i] = 0.20; if(err[i] < 9.e9) { // Ignore missing bands (otherwise, they affect evidence) lnL_norm += 0.9189385332 + log(err[i]); } @@ -91,10 +97,13 @@ struct TStellarData { obj_id = rhs.obj_id; l = rhs.l; b = rhs.b; + pi = rhs.pi; + pi_err = rhs.pi_err; for(unsigned int i=0; i &pix_name); - - -#endif // _STELLAR_DATA_H__ \ No newline at end of file +// Return names of pixels in input file +void get_input_pixels( + std::string fname, + std::vector &pix_name, + const std::string &base="/photometry" +); + +// Return attributes describing pixels in input file, given list of pixel names +void get_pixel_props( + const std::string& fname, + const std::vector& pix_name, + std::vector& l, + std::vector& b, + std::vector& EBV, + std::vector& nside, + std::vector& healpix_index, + const std::string &base="/photometry" +); + +#endif // _STELLAR_DATA_H__ diff --git a/src/definitions.h b/src/definitions.h index 6844a1e..c9de569 100644 --- a/src/definitions.h +++ b/src/definitions.h @@ -1,26 +1,26 @@ /* * definitions.h - * + * * Definitions needed by a number of header/source files. - * + * * This file is part of bayestar. * Copyright 2012 Gregory Green - * + * * Bayestar is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. - * + * */ #ifndef _DEFINITIONS_H__ @@ -79,6 +79,10 @@ inline bool is_inf_replacement(double x) { #define INV_SQRT2 0.70710678118654746 #endif // INV_SQRT2 +#ifndef SQRT3 +#define SQRT3 1.7320508075688772 +#endif // SQRT3 + #ifndef SQRT2PI #define SQRT2PI 2.5066282746310002 #endif // SQRT2PI @@ -88,4 +92,15 @@ inline bool is_inf_replacement(double x) { #endif // LN10 -#endif // _DEFINITIONS_H__ \ No newline at end of file +/************************************************************************* + * Custom types + *************************************************************************/ + +// Easily switch between 32- and 64-bit floating-point types +typedef float floating_t; +#ifndef CV_FLOATING_TYPE +#define CV_FLOATING_TYPE CV_32F +#endif // CV_FLOATING_TYPE + + +#endif // _DEFINITIONS_H__ diff --git a/src/gaussian_process.cpp b/src/gaussian_process.cpp new file mode 100644 index 0000000..c1c40c9 --- /dev/null +++ b/src/gaussian_process.cpp @@ -0,0 +1,177 @@ +/* + * gaussian_process.cpp + * + * Gaussian-process-related functions for bayestar. + * + * This file is part of bayestar. + * Copyright 2018 Gregory Green + * + * Bayestar is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + * + */ + + +#include "gaussian_process.h" + + +//void conditional_gaussian_matrices( +// MatrixXd& C11, MatrixXd& C12, MatrixXd& C22, +// MatrixXd& C11_cond, MatrixXd& A_cond) +//{ +// // Calculates the matrices necessary to quickly +// // compute conditional Gaussian distributions. +// +// A_cond = C12 * C22.inverse(); // \mu_{1|2} = A (y_2 - \mu_2) +// C11_cond = C11 - A * C12.transpose(); // \Sigma_{11|2} +//} + + +void conditional_gaussian_scalar( + const Eigen::MatrixXd& C_inv, unsigned int idx, + double& inv_var, Eigen::MatrixXd& A_cond) +{ + // Calculates p(x_i | x_{\i}), where p(x) is a Gaussian, + // and all the elements of the vector x except x_i are + // given. + // + // Inputs: + // C_inv (MatrixXd): Covariance matrix of the entire + // vector x. + // idx (unsigned int): The element i in the vector x + // to calculate the probability + // density function of. + // + // Sets the following references: + // inv_var (double): the inverse variance of x_i + // A_cond (MatrixXd): A matrix that takes the values + // of x_{\i} and gives the mean x_i. + + inv_var = C_inv(idx, idx); + A_cond = (-1./inv_var) * C_inv.row(idx); +} + + +//void remove_matrix_rowcol(MatrixXd& m, unsigned int idx) { +// // Removes the specified row and column from a matrix. +// // +// // Based on these StackOverflow answers by raahlb and Andrew: +// // * +// // * +// +// unsigned int n_rows = matrix.rows(); +// unsigned int n_cols = matrix.cols(); +// +// if(idx < n_rows-1) { +// matrix.block(idx, 0, n_rows-idx-1, n_cols) = matrix.bottomRows(n_rows-idx-1); +// } +// if(idx < n_cols-1) { +// matrix.block(0, idx, n_rows-1, n_cols-idx-1) = matrix.rightCols(n_cols-idx-1); +// } +// +// matrix.conservativeResize(n_rows-1, n_cols-1); +//} + +const double pi_over_180 = 3.141592653589793238 / 180.; + + +void distance_matrix_lonlat( + const std::vector& lon, + const std::vector& lat, + Eigen::MatrixXd& d2) +{ + // Fills the matrix d2 with the pairwise squared angular + // distances (in rad) between the given (lon, lat) pairs. + // + // These distances are approximate. They are actually 3D + // distances between points on a unit sphere, rather than + // great-circle distances. + + // Convert (lon, lat) to (x, y, z) + uint32_t n_coords = lon.size(); + std::vector xyz; + xyz.reserve(3*n_coords); + + //std::cerr << "Calculating (x, y, z) of pixels ..." << std::endl; + + double cos_lon, cos_lat, sin_lon, sin_lat; + for(int i=0; i& lon, + const std::vector& lat, + const std::vector& dist, + std::function& kernel, + std::vector& inv_cov) +{ + // Calculates a set of inverse covariance matrices - one per + // distance. Each matrix gives the inverse covariance between + // the coordinate (specified by lon, lat) at a given distance + // (specified by dist). Works with a custom kernel function, + // which maps distance^2 -> covariance. The inverse + // covariance matrices are stored in inv_cov. + + // Calculate pairwise angular distances + Eigen::MatrixXd d2_mat; + distance_matrix_lonlat(lon, lat, d2_mat); + + //std::cerr << "Transverse distances:" << std::endl + // << d2_mat << std::endl; + + // Generate one covariance matrix per physical distance + for(double d : dist) { + //std::cerr << "Calculating Cov^-1 at distance = " << d << " pc ..." << std::endl; + UniqueMatrixXd C = std::make_unique(); + //UniqueMatrixXd C = std::unique_ptr(); + C->resize(d2_mat.rows(), d2_mat.cols()); + *C = d2_mat.unaryExpr([kernel, d](double d2) -> double { + // Angular distance scaled by physical distance + return kernel(d*d * d2); + }).inverse(); + + //std::cerr << std::endl << "dist = " << d << " pc" << std::endl; + //std::cerr << std::endl << *C << std::endl; + + inv_cov.push_back(std::move(C)); + } +} diff --git a/src/gaussian_process.h b/src/gaussian_process.h new file mode 100644 index 0000000..6337f77 --- /dev/null +++ b/src/gaussian_process.h @@ -0,0 +1,63 @@ +/* + * gaussian_process.h + * + * Gaussian-process-related functions for bayestar. + * + * This file is part of bayestar. + * Copyright 2018 Gregory Green + * + * Bayestar is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + * + */ + +#ifndef _GAUSSIAN_PROCESS_H_ +#define _GAUSSIAN_PROCESS_H_ + + +#include +#include +#include +#include +#include + +#include + +//typedef Eigen::Matrix MatrixXd; +typedef std::shared_ptr SharedMatrixXd; +typedef std::unique_ptr UniqueMatrixXd; +//typedef std::shared_ptr > SharedVectord; + +//void conditional_gaussian(MatrixXd& C11, MatrixXd& C12, MatrixXd& C22, MatrixXd& C11_cond, MatrixXd& A_cond); + + +void conditional_gaussian_scalar( + const Eigen::MatrixXd& C_inv, unsigned int idx, + double& inv_var, Eigen::MatrixXd& A_cond); + +void distance_matrix_lonlat( + const std::vector& lon, + const std::vector& lat, + Eigen::MatrixXd& d2); + +void inv_cov_lonlat( + const std::vector& lon, + const std::vector& lat, + const std::vector& dist, + std::function& kernel, + std::vector& inv_cov); + + +#endif // _GAUSSIAN_PROCESS_H_ diff --git a/src/gp.cpp b/src/gp.cpp new file mode 100644 index 0000000..da21cfd --- /dev/null +++ b/src/gp.cpp @@ -0,0 +1,12 @@ +#ifndef _GP_H__ +#define _GP_H__ + + +#include +#include +#include +#include +#include +#include + +#include diff --git a/src/h5utils.cpp b/src/h5utils.cpp index 55e3697..25641a6 100644 --- a/src/h5utils.cpp +++ b/src/h5utils.cpp @@ -50,33 +50,34 @@ int H5Utils::DONOTCREATE = (1 << 2); * is returned. * */ -H5::H5File* H5Utils::openFile(const std::string& fname, int accessmode) { - H5::H5File* file = NULL; - +std::unique_ptr H5Utils::openFile( + const std::string& fname, + int accessmode) +{ // Read/Write access if((accessmode & H5Utils::READ) && (accessmode & H5Utils::WRITE)) { try { - file = new H5::H5File(fname.c_str(), H5F_ACC_RDWR); + return std::unique_ptr(new H5::H5File(fname.c_str(), H5F_ACC_RDWR)); } catch(const H5::FileIException& err_does_not_exist) { - if(accessmode & H5Utils::DONOTCREATE) { - file = NULL; + if(accessmode& H5Utils::DONOTCREATE) { + return std::unique_ptr(nullptr); } else { - file = new H5::H5File(fname.c_str(), H5F_ACC_TRUNC); + return std::unique_ptr(new H5::H5File(fname.c_str(), H5F_ACC_TRUNC)); } } // Read-only access } else if(accessmode & H5Utils::READ) { try { - file = new H5::H5File(fname.c_str(), H5F_ACC_RDONLY); + return std::unique_ptr(new H5::H5File(fname.c_str(), H5F_ACC_RDONLY)); } catch(const H5::FileIException& err_does_not_exist) { - file = NULL; + return std::unique_ptr(nullptr); } // Other (incorrect) access mode } else { std::cerr << "openFile: Invalid access mode." << std::endl; } - return file; + return std::unique_ptr(nullptr); } /* @@ -89,15 +90,17 @@ H5::H5File* H5Utils::openFile(const std::string& fname, int accessmode) { * does not yet exist. * */ -H5::Group* H5Utils::openGroup(H5::H5File* file, const std::string& name, int accessmode) { - H5::Group* group = NULL; - +std::unique_ptr H5Utils::openGroup( + H5::H5File& file, + const std::string& name, + int accessmode) +{ // User does not want to create group if(accessmode & H5Utils::DONOTCREATE) { try { - group = new H5::Group(file->openGroup(name.c_str())); + return std::unique_ptr(new H5::Group(file.openGroup(name.c_str()))); } catch(const H5::FileIException& err_does_not_exist) { - return group; + return std::unique_ptr(nullptr); } } @@ -105,33 +108,29 @@ H5::Group* H5Utils::openGroup(H5::H5File* file, const std::string& name, int acc std::stringstream ss(name); std::stringstream path; std::string gp_name; + std::unique_ptr group; while(std::getline(ss, gp_name, '/')) { path << "/" << gp_name; - if(group != NULL) { delete group; } try { - group = new H5::Group(file->openGroup(path.str().c_str())); + group.reset(new H5::Group(file.openGroup(path.str().c_str()))); } catch(const H5::FileIException& err_does_not_exist) { - group = new H5::Group(file->createGroup(path.str().c_str())); + group.reset(new H5::Group(file.createGroup(path.str().c_str()))); } } - return group; + return std::move(group); } /* * Opens an existing dataset. * */ -H5::DataSet* H5Utils::openDataSet(H5::H5File* file, const std::string& name) { - H5::DataSet* dataset = NULL; - +std::unique_ptr H5Utils::openDataSet(H5::H5File& file, const std::string& name) { try { - dataset = new H5::DataSet(file->openDataSet(name.c_str())); + return std::unique_ptr(new H5::DataSet(file.openDataSet(name.c_str()))); } catch(const H5::FileIException& err_does_not_exist) { - return dataset; + return std::unique_ptr(nullptr); } - - return dataset; } /* @@ -140,35 +139,35 @@ H5::DataSet* H5Utils::openDataSet(H5::H5File* file, const std::string& name) { * */ -H5::Attribute H5Utils::openAttribute(H5::Group* group, const std::string& name, H5::DataType& dtype, H5::DataSpace& dspace) { +H5::Attribute H5Utils::openAttribute(H5::Group& group, const std::string& name, H5::DataType& dtype, H5::DataSpace& dspace) { try { - return group->openAttribute(name); + return group.openAttribute(name); } catch(H5::AttributeIException err_att_does_not_exist) { - return group->createAttribute(name, dtype, dspace); + return group.createAttribute(name, dtype, dspace); } } -H5::Attribute H5Utils::openAttribute(H5::DataSet* dataset, const std::string& name, H5::DataType& dtype, H5::DataSpace& dspace) { +H5::Attribute H5Utils::openAttribute(H5::DataSet& dataset, const std::string& name, H5::DataType& dtype, H5::DataSpace& dspace) { try { - return dataset->openAttribute(name); + return dataset.openAttribute(name); } catch(H5::AttributeIException err_att_does_not_exist) { - return dataset->createAttribute(name, dtype, dspace); + return dataset.createAttribute(name, dtype, dspace); } } -H5::Attribute H5Utils::openAttribute(H5::Group* group, const std::string& name, H5::StrType& strtype, H5::DataSpace& dspace) { +H5::Attribute H5Utils::openAttribute(H5::Group& group, const std::string& name, H5::StrType& strtype, H5::DataSpace& dspace) { try { - return group->openAttribute(name); + return group.openAttribute(name); } catch(H5::AttributeIException err_att_does_not_exist) { - return group->createAttribute(name, strtype, dspace); + return group.createAttribute(name, strtype, dspace); } } -H5::Attribute H5Utils::openAttribute(H5::DataSet* dataset, const std::string& name, H5::StrType& strtype, H5::DataSpace& dspace) { +H5::Attribute H5Utils::openAttribute(H5::DataSet& dataset, const std::string& name, H5::StrType& strtype, H5::DataSpace& dspace) { try { - return dataset->openAttribute(name); + return dataset.openAttribute(name); } catch(H5::AttributeIException err_att_does_not_exist) { - return dataset->createAttribute(name, strtype, dspace); + return dataset.createAttribute(name, strtype, dspace); } } @@ -178,9 +177,9 @@ H5::Attribute H5Utils::openAttribute(H5::DataSet* dataset, const std::string& na * */ -bool H5Utils::group_exists(const std::string& name, H5::H5File* file) { +bool H5Utils::group_exists(const std::string& name, H5::H5File& file) { try { - file->openGroup(name); + file.openGroup(name); } catch(H5::FileIException err_gp_does_not_exist) { return false; } @@ -188,9 +187,9 @@ bool H5Utils::group_exists(const std::string& name, H5::H5File* file) { return true; } -bool H5Utils::group_exists(const std::string& name, H5::Group* group) { +bool H5Utils::group_exists(const std::string& name, H5::Group& group) { try { - group->openGroup(name); + group.openGroup(name); } catch(H5::GroupIException err_gp_does_not_exist) { return false; } @@ -198,9 +197,9 @@ bool H5Utils::group_exists(const std::string& name, H5::Group* group) { return true; } -bool H5Utils::dataset_exists(const std::string& name, H5::H5File* file) { +bool H5Utils::dataset_exists(const std::string& name, H5::H5File& file) { try { - file->openDataSet(name); + file.openDataSet(name); } catch(H5::FileIException err_dset_does_not_exist) { return false; } @@ -208,9 +207,9 @@ bool H5Utils::dataset_exists(const std::string& name, H5::H5File* file) { return true; } -bool H5Utils::dataset_exists(const std::string& name, H5::Group* group) { +bool H5Utils::dataset_exists(const std::string& name, H5::Group& group) { try { - group->openDataSet(name); + group.openDataSet(name); } catch(H5::GroupIException err_dset_does_not_exist) { return false; } @@ -229,25 +228,23 @@ bool H5Utils::dataset_exists(const std::string& name, H5::Group* group) { */ template -bool add_watermark_helper(const std::string &filename, const std::string &group_name, const std::string &attribute_name, const T &value, - const H5::DataType *dtype, const H5::StrType *strtype, const H5::DataSpace &dspace) { +bool add_watermark_helper(const std::string& filename, const std::string& group_name, const std::string& attribute_name, const T& value, + const H5::DataType* dtype, const H5::StrType* strtype, const H5::DataSpace& dspace) { if((strtype == NULL) && (dtype == NULL)) { return false; } - H5::H5File *file = H5Utils::openFile(filename); - if(file == NULL) { return false; } - - H5::Group *group = NULL; + std::unique_ptr file = H5Utils::openFile(filename); + if(!file) { return false; } bool is_group = true; + std::unique_ptr group; try { - group = H5Utils::openGroup(file, group_name); + group = H5Utils::openGroup(*file, group_name); } catch(H5::FileIException err_not_group) { is_group = false; } if(is_group) { - if(group == NULL) { - delete file; + if(!group) { return false; } @@ -258,12 +255,9 @@ bool add_watermark_helper(const std::string &filename, const std::string &group_ H5::Attribute att = group->createAttribute(attribute_name, *strtype, dspace); att.write(*strtype, reinterpret_cast(&value)); } - - delete group; } else { - H5::DataSet *dataset = H5Utils::openDataSet(file, group_name); - if(dataset == NULL) { - delete file; + std::unique_ptr dataset = H5Utils::openDataSet(*file, group_name); + if(!dataset) { return false; } @@ -274,16 +268,13 @@ bool add_watermark_helper(const std::string &filename, const std::string &group_ H5::Attribute att = dataset->createAttribute(attribute_name, *strtype, dspace); att.write(*strtype, reinterpret_cast(&value)); } - - delete dataset; } - delete file; return true; } template -bool add_watermark_helper(const std::string &filename, const std::string &group_name, const std::string &attribute_name, const T &value, const H5::DataType *dtype) { +bool add_watermark_helper(const std::string& filename, const std::string& group_name, const std::string& attribute_name, const T& value, const H5::DataType *dtype) { int rank = 1; hsize_t dim = 1; H5::DataSpace dspace(rank, &dim); @@ -292,44 +283,165 @@ bool add_watermark_helper(const std::string &filename, const std::string &group_ } template<> -bool H5Utils::add_watermark(const std::string &filename, const std::string &group_name, const std::string &attribute_name, const bool &value) { +bool H5Utils::add_watermark(const std::string& filename, const std::string& group_name, const std::string& attribute_name, const bool& value) { H5::DataType dtype = H5::PredType::NATIVE_UCHAR; return add_watermark_helper(filename, group_name, attribute_name, value, &dtype); } template<> -bool H5Utils::add_watermark(const std::string &filename, const std::string &group_name, const std::string &attribute_name, const float &value) { +bool H5Utils::add_watermark(const std::string& filename, const std::string& group_name, const std::string& attribute_name, const float& value) { H5::DataType dtype = H5::PredType::NATIVE_FLOAT; return add_watermark_helper(filename, group_name, attribute_name, value, &dtype); } template<> -bool H5Utils::add_watermark(const std::string &filename, const std::string &group_name, const std::string &attribute_name, const double &value) { +bool H5Utils::add_watermark(const std::string& filename, const std::string& group_name, const std::string& attribute_name, const double& value) { H5::DataType dtype = H5::PredType::NATIVE_DOUBLE; return add_watermark_helper(filename, group_name, attribute_name, value, &dtype); } template<> -bool H5Utils::add_watermark(const std::string &filename, const std::string &group_name, const std::string &attribute_name, const uint32_t &value) { +bool H5Utils::add_watermark(const std::string& filename, const std::string& group_name, const std::string& attribute_name, const uint32_t& value) { H5::DataType dtype = H5::PredType::NATIVE_UINT32; return add_watermark_helper(filename, group_name, attribute_name, value, &dtype); } template<> -bool H5Utils::add_watermark(const std::string &filename, const std::string &group_name, const std::string &attribute_name, const uint64_t &value) { +bool H5Utils::add_watermark(const std::string& filename, const std::string& group_name, const std::string& attribute_name, const uint64_t& value) { H5::DataType dtype = H5::PredType::NATIVE_UINT64; return add_watermark_helper(filename, group_name, attribute_name, value, &dtype); } template<> -bool H5Utils::add_watermark(const std::string &filename, const std::string &group_name, const std::string &attribute_name, const std::string &value) { +bool H5Utils::add_watermark(const std::string& filename, const std::string& group_name, const std::string& attribute_name, const std::string& value) { H5::StrType strtype(0, H5T_VARIABLE); H5::DataSpace dspace(H5S_SCALAR); return add_watermark_helper(filename, group_name, attribute_name, value, NULL, &strtype, dspace); } template -bool H5Utils::add_watermark(const std::string &filename, const std::string &group_name, const std::string &attribute_name, const T &value) { +bool H5Utils::add_watermark(const std::string& filename, const std::string& group_name, const std::string& attribute_name, const T& value) { // Unknown type return false; } + + + +// Read attribute from dataset + +template +T read_attribute_helper(H5::Attribute& attribute, H5::DataType& dtype) { + T value; + attribute.read(dtype, &value); + return value; +} + +template +T read_attribute_helper(H5::DataSet& dataset, const std::string& name, H5::DataType& dtype) { + H5::Attribute attribute = dataset.openAttribute(name); + return read_attribute_helper(attribute, dtype); +} + +template<> +double H5Utils::read_attribute(H5::DataSet& dataset, const std::string& name) { + H5::DataType dtype = H5::PredType::NATIVE_DOUBLE; + return read_attribute_helper(dataset, name, dtype); +} + +template<> +float H5Utils::read_attribute(H5::DataSet& dataset, const std::string& name) { + H5::DataType dtype = H5::PredType::NATIVE_FLOAT; + return read_attribute_helper(dataset, name, dtype); +} + +// Read attribute from group +template +T read_attribute_helper(H5::Group& g, const std::string& name) { + H5::PredType dtype = H5Utils::get_dtype(); + H5::Attribute attribute = g.openAttribute(name); + return read_attribute_helper(attribute, dtype); +} + +template<> +double H5Utils::read_attribute(H5::Group& g, const std::string& name) { + return read_attribute_helper(g, name); +} + +template<> +float H5Utils::read_attribute(H5::Group& g, const std::string& name) { + return read_attribute_helper(g, name); +} + +template<> +uint32_t H5Utils::read_attribute(H5::Group& g, const std::string& name) { + return read_attribute_helper(g, name); +} + +template<> +uint64_t H5Utils::read_attribute(H5::Group& g, const std::string& name) { + return read_attribute_helper(g, name); +} + +// Read attribute that is 1D array +template +void H5Utils::read_attribute_1d_helper(H5::Attribute& attribute, std::vector &ret) { + // Check that attribute is 1D + H5::DataSpace dataspace = attribute.getSpace(); + const hsize_t n_dims = dataspace.getSimpleExtentNdims(); + assert(n_dims == 1); + + // Get length of array + H5::PredType type = H5Utils::get_dtype(); + hsize_t length; + dataspace.getSimpleExtentDims(&length); + + // Read in array + ret.resize(length); + attribute.read(H5Utils::get_dtype(), ret.data()); +} + +template<> +std::vector H5Utils::read_attribute_1d(H5::Attribute& attribute) { + std::vector a; + read_attribute_1d_helper(attribute, a); + return a; +} + +template<> +std::vector H5Utils::read_attribute_1d(H5::Attribute& attribute) { + std::vector a; + read_attribute_1d_helper(attribute, a); + return a; +} + + +/* + * Convert C++ data types to HDF5 data types + * + */ + +template<> +H5::PredType H5Utils::get_dtype() { + return H5::PredType::NATIVE_FLOAT; +} + +template<> +H5::PredType H5Utils::get_dtype() { + return H5::PredType::NATIVE_DOUBLE; +} + +template<> +H5::PredType H5Utils::get_dtype() { + return H5::PredType::NATIVE_UINT32; +} + +template<> +H5::PredType H5Utils::get_dtype() { + return H5::PredType::NATIVE_UINT64; +} + +template<> +H5::PredType H5Utils::get_dtype() { + return H5::PredType::NATIVE_UCHAR; +} + diff --git a/src/h5utils.h b/src/h5utils.h index 1a4cbbf..0221816 100644 --- a/src/h5utils.h +++ b/src/h5utils.h @@ -32,6 +32,9 @@ #include #include #include +#include +#include +#include #include namespace H5Utils { @@ -40,42 +43,177 @@ namespace H5Utils { extern int WRITE; extern int DONOTCREATE; - H5::H5File* openFile(const std::string &fname, int accessmode = (READ | WRITE)); - H5::Group* openGroup(H5::H5File* file, const std::string &name, int accessmode = 0); - H5::DataSet* openDataSet(H5::H5File* file, const std::string &name); + std::unique_ptr openFile(const std::string& fname, int accessmode = (READ | WRITE)); + std::unique_ptr openGroup(H5::H5File& file, const std::string& name, int accessmode = 0); + std::unique_ptr openDataSet(H5::H5File& file, const std::string& name); - H5::Attribute openAttribute(H5::Group* group, const std::string &name, H5::DataType &dtype, H5::DataSpace &dspace); - H5::Attribute openAttribute(H5::DataSet* dataset, const std::string &name, H5::DataType &dtype, H5::DataSpace &dspace); - H5::Attribute openAttribute(H5::Group* group, const std::string &name, H5::StrType &strtype, H5::DataSpace &dspace); - H5::Attribute openAttribute(H5::DataSet* dataset, const std::string &name, H5::StrType &strtype, H5::DataSpace &dspace); + H5::Attribute openAttribute(H5::Group& group, const std::string& name, H5::DataType& dtype, H5::DataSpace& dspace); + H5::Attribute openAttribute(H5::DataSet& dataset, const std::string& name, H5::DataType& dtype, H5::DataSpace& dspace); + H5::Attribute openAttribute(H5::Group& group, const std::string& name, H5::StrType& strtype, H5::DataSpace& dspace); + H5::Attribute openAttribute(H5::DataSet& dataset, const std::string& name, H5::StrType& strtype, H5::DataSpace& dspace); + + // Read attribute from dataset + template + T read_attribute(H5::DataSet& dataset, const std::string& name); + + template<> + double read_attribute(H5::DataSet& dataset, const std::string& name); + + template<> + float read_attribute(H5::DataSet& dataset, const std::string& name); + + // Read attribute from group + template + T read_attribute(H5::Group& group, const std::string& name); + + template<> + float read_attribute(H5::Group& g, const std::string& name); + + template<> + double read_attribute(H5::Group& g, const std::string& name); + + template<> + uint32_t read_attribute(H5::Group& g, const std::string& name); + + template<> + uint64_t read_attribute(H5::Group& g, const std::string& name); - bool group_exists(const std::string &name, H5::H5File* file); - bool group_exists(const std::string &name, H5::Group* group); + bool group_exists(const std::string& name, H5::H5File& file); + bool group_exists(const std::string& name, H5::Group& group); - bool dataset_exists(const std::string &name, H5::H5File* file); - bool dataset_exists(const std::string &name, H5::Group* group); + bool dataset_exists(const std::string& name, H5::H5File& file); + bool dataset_exists(const std::string& name, H5::Group& group); + + // Read attribute directly + template + void read_attribute_1d_helper(H5::Attribute& attribute, std::vector &ret); + + template + std::vector read_attribute_1d(H5::Attribute& attribute); + + template<> + std::vector read_attribute_1d(H5::Attribute& attribute); + + template<> + std::vector read_attribute_1d(H5::Attribute& attribute); + // Write attribute to group or dataset in file template - bool add_watermark(const std::string &filename, const std::string &group_name, const std::string &attribute_name, const T &value); + bool add_watermark(const std::string& filename, const std::string& group_name, const std::string& attribute_name, const T& value); template<> - bool add_watermark(const std::string &filename, const std::string &group_name, const std::string &attribute_name, const bool &value); + bool add_watermark(const std::string& filename, const std::string& group_name, const std::string& attribute_name, const bool& value); template<> - bool add_watermark(const std::string &filename, const std::string &group_name, const std::string &attribute_name, const float &value); + bool add_watermark(const std::string& filename, const std::string& group_name, const std::string& attribute_name, const float& value); template<> - bool add_watermark(const std::string &filename, const std::string &group_name, const std::string &attribute_name, const double &value); + bool add_watermark(const std::string& filename, const std::string& group_name, const std::string& attribute_name, const double& value); template<> - bool add_watermark(const std::string &filename, const std::string &group_name, const std::string &attribute_name, const uint32_t &value); + bool add_watermark(const std::string& filename, const std::string& group_name, const std::string& attribute_name, const uint32_t& value); template<> - bool add_watermark(const std::string &filename, const std::string &group_name, const std::string &attribute_name, const uint64_t &value); + bool add_watermark(const std::string& filename, const std::string& group_name, const std::string& attribute_name, const uint64_t& value); template<> - bool add_watermark(const std::string &filename, const std::string &group_name, const std::string &attribute_name, const std::string &value); - + bool add_watermark(const std::string& filename, const std::string& group_name, const std::string& attribute_name, const std::string& value); + + // Convert C++ data types to HDF5 data types + template + H5::PredType get_dtype(); + + template<> + H5::PredType get_dtype(); + + template<> + H5::PredType get_dtype(); + + template<> + H5::PredType get_dtype(); + + template<> + H5::PredType get_dtype(); + + template<> + H5::PredType get_dtype(); + + // Create dataset from 1D array. + template + std::unique_ptr createDataSet( + H5::H5File& file, + const std::string& group, + const std::string& dset, + const std::vector& data, + uint8_t gzip=3, // 0 for no compression, 9 for max. compression + uint64_t chunk_size=1048576); // in Bytes + } + +/* + * Create dataset from 1D array. + * + */ +template +std::unique_ptr H5Utils::createDataSet( + H5::H5File& file, + const std::string& group, + const std::string& dset, + const std::vector& data, + uint8_t gzip, + uint64_t chunk_size) +{ + // Get group containing dataset + //std::cerr << "Opening group " << group << std::endl; + std::unique_ptr g = H5Utils::openGroup( + file, + group, + H5Utils::READ | H5Utils::WRITE); + if(!g) { + std::cerr << "Failed to open group!" << std::endl; + } + + // Datatype + //std::cerr << "Datatype" << std::endl; + H5::DataType dtype = get_dtype(); + + // Dataspace + //std::cerr << "Dataspace" << std::endl; + hsize_t dim = data.size(); + H5::DataSpace dspace(1, &dim); + //std::cerr << "dim = " << dim << std::endl; + + // Property List + //std::cerr << "Chunking" << std::endl; + H5::DSetCreatPropList plist; + + hsize_t n_per_chunk = chunk_size / sizeof(T); + if(n_per_chunk < 1) { + n_per_chunk = 1; + } else if(n_per_chunk > data.size()) { + n_per_chunk = data.size(); + } + plist.setChunk(1, &n_per_chunk); // Chunk size + //std::cerr << "n_per_chunk = " << n_per_chunk << std::endl; + + //std::cerr << "Deflate" << std::endl; + plist.setDeflate(gzip); // DEFLATE compression level (min=0, max=9) + //std::cerr << "gzip = " << (unsigned int)gzip << std::endl; + + // Create dataset + //std::cerr << "Dataset" << std::endl; + std::unique_ptr dataset = std::unique_ptr( + new H5::DataSet(g->createDataSet(dset, dtype, dspace, plist)) + ); + + // Write data + //std::cerr << "write" << std::endl; + dataset->write(data.data(), dtype); + + //std::cerr << "returning" << std::endl; + return std::move(dataset); +} + + #endif // _H5UTILS_H__ diff --git a/src/healpix_tree.cpp b/src/healpix_tree.cpp new file mode 100644 index 0000000..c3b5022 --- /dev/null +++ b/src/healpix_tree.cpp @@ -0,0 +1,117 @@ +/* + * healpix_tree.cpp + * + * Traverse a tree structure representing a nested HEALPix map, + * stored in an HDF5 file by nested groups. + * + * This file is part of bayestar. + * Copyright 2018 Gregory Green + * + * Bayestar is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + * + */ + +#include "healpix_tree.h" + + +void healpix_loc2digits( + uint32_t nside, + uint32_t pix_idx, + std::vector& digits) +{ + // Converts a healpix (nside, index) specification + // to a set of digits representing the location of + // the pixel in the nested scheme. + // + // For example, the digits + // (10, 0, 1, 3, 1) + // corresponds to selecting the 10th (of 12) + // top-level pixels, then the 0th (of 4) nested + // pixel, then the 1st (of 4) nested pixel, etc. + // The above digits also correspond to nside = 16, + // and + // pix_idx = 1 + 4*3 + 4^2*1 + 4^3*0 + 4^4*10 + + //std::cerr << "healpix_loc2digits(" + // << "nside=" << nside << ", " + // << "pix_idx=" << pix_idx + // << ")" << std::endl; + + // Take log_2(nside) + 1 + uint32_t n_levels = 1; + while(nside >>= 1) { + n_levels++; + } + //std::cerr << "n_levels = " << n_levels << std::endl; + + // Read off the digits, from last to first + digits.resize(n_levels); + uint8_t d; + + for(int i=0; i healtree_get_dataset( + H5::H5File& file, + uint32_t nside, + uint32_t pix_idx) +{ + // Returns the dataset containing the requested + // pixel, described by (nside, pix_idx). The + // file is assumed to contain nested groups, + // representing a nested tree structure that + // mirrors a HEALPix map (a "HEALTree"). + // + // For example, the pixel described by the digits + // (9, 1, 0, 3, 3, 2, 0) might be contained in + // the dataset "/9/1/0/3/3". + + // Convert location to digits + std::vector digits; + healpix_loc2digits(nside, pix_idx, digits); + + // Find deepest group level present in file + std::stringstream g; + //for(; depth +#include +#include +#include + +#include "h5utils.h" + + +std::unique_ptr healtree_get_dataset(H5::H5File& file, uint32_t nside, uint32_t pix_idx); + +void healpix_loc2digits(uint32_t nside, uint32_t pix_idx, std::vector& digits); + + +#endif // _HEALPIX_TREE_H__ diff --git a/src/interpolation.h b/src/interpolation.h index 58c2ec8..144a28e 100644 --- a/src/interpolation.h +++ b/src/interpolation.h @@ -1,28 +1,28 @@ /* * interpolation.h - * + * * Classes which implement linear, bilinear and multilinear * interpolation on arbitrary objects. The objects must have * addition and scalar multiplication defined on them. - * + * * This file is part of bayestar. * Copyright 2012 Gregory Green - * + * * Bayestar is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. - * + * */ #ifndef __INTERPOLATION_H_ @@ -43,20 +43,20 @@ class TLinearInterp { double *f_x; double x_min, x_max, dx, inv_dx; unsigned int N; - + public: typedef double (*func1d_t)(double x); - + TLinearInterp(double _x_min, double _x_max, unsigned int _N); TLinearInterp(func1d_t func, double _x_min, double _x_max, unsigned int _N); ~TLinearInterp(); - + double operator()(double x) const; double& operator[](unsigned int index); - + double get_x(unsigned int index) const; double dfdx(double x) const; - + void fill(func1d_t func); }; @@ -72,21 +72,22 @@ class TBilinearInterp { double y_min, y_max, dy, inv_dy; double dxdy, inv_dxdy; unsigned int Nx, Ny; - + public: typedef T (*func2d_t)(double x, double y); typedef T* (*func2d_ptr_t)(double x, double y); - + TBilinearInterp(double _x_min, double _x_max, unsigned int Nx, double _y_min, double _y_max, unsigned int Ny); TBilinearInterp(func2d_t func, double _x_min, double _x_max, unsigned int Nx, double _y_min, double _y_max, unsigned int Ny); TBilinearInterp(func2d_ptr_t func, double _x_min, double _x_max, unsigned int Nx, double _y_min, double _y_max, unsigned int Ny); ~TBilinearInterp(); - + T operator()(double x, double y) const; T& operator[](unsigned int index); unsigned int get_index(double x, double y) const; + unsigned int get_flat_index(unsigned int i, unsigned int j) const; void get_xy(unsigned int i, unsigned int j, double &x, double &y) const; - + void fill(func2d_t func); void fill(func2d_ptr_t func); }; @@ -147,7 +148,7 @@ unsigned int TBilinearInterp::get_index(double x, double y) const { template T TBilinearInterp::operator()(double x, double y) const { double idx = floor((x-x_min)*inv_dx); - + // DEBUG: if((idx < 0) || (idx >= Nx)) { #pragma omp critical @@ -161,16 +162,16 @@ T TBilinearInterp::operator()(double x, double y) const { std::cerr << "inv_dy = " << inv_dy << std::endl; } } - + //#pragma omp critical //{ // std::cout << "0 <= " << idx << " < " << Nx << std::endl; //} - + assert((idx >= 0) && (idx < Nx)); - + double idy = floor((y-y_min)*inv_dy); - + // DEBUG: if((idy < 0) || (idy >= Ny)) { #pragma omp critical @@ -184,14 +185,14 @@ T TBilinearInterp::operator()(double x, double y) const { std::cerr << "inv_dy = " << inv_dy << std::endl; } } - + //#pragma omp critical //{ // std::cout << "0 <= " << idy << " < " << Nx << std::endl; //} - + assert((idy >= 0) && (idy < Ny)); - + double Delta_x = x - x_min - dx*idx; double Delta_y = y - y_min - dy*idy; unsigned int N00 = (unsigned int)idx + Nx*(unsigned int)idy; @@ -211,8 +212,8 @@ T& TBilinearInterp::operator[](unsigned int index) { template void TBilinearInterp::get_xy(unsigned int i, unsigned int j, double &x, double &y) const { assert((i < Nx) && (j < Ny)); - x = dx*(double)i - x_min; - y = dy*(double)j - y_min; + x = dx*(double)i + x_min; + y = dy*(double)j + y_min; } template @@ -237,6 +238,11 @@ void TBilinearInterp::fill(func2d_ptr_t func) { } } +template +unsigned int TBilinearInterp::get_flat_index(unsigned int i, unsigned int j) const { + return i + Nx*j; +} + // N-Dimensional (multilinear) interpolation //////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -247,36 +253,36 @@ class TMultiLinearInterp { double *min, *max, *inv_dx; unsigned int *N; unsigned int length; - + unsigned int ndim; unsigned int *coeff; - + std::vector filled; T empty; - + double *lower; unsigned int *Delta_idx; unsigned int N_Delta; - + public: typedef T (*func_t)(double *x); typedef T* (*func_ptr_t)(double *x); - + TMultiLinearInterp(const double* _min, const double* _max, const unsigned int* _N, unsigned int _ndim, T& _empty); ~TMultiLinearInterp(); - + T operator()(const double *x); bool operator()(const double *x, T &res); - + void set(const double *x, T &fx); - + bool fill(const double *x, T *fx); bool fill(typename std::vector::iterator begin, typename std::vector::iterator end); void fill(func_t func); void fill(func_ptr_t func); - + void get_filled(std::vector &ret); - + private: int get_index(const double *x) const; int get_lower(const double *x) const; @@ -302,13 +308,13 @@ TMultiLinearInterp::TMultiLinearInterp(const double *_min, const double *_max coeff[i] = length; length *= N[i]; } - + f = new T[length]; filled.resize(length); std::fill(filled.begin(), filled.end(), false); - + lower = new double[ndim]; - + // Compute Deltas (difference in index from lower corner) to corners of box N_Delta = (1 << ndim); Delta_idx = new unsigned int[N_Delta]; @@ -389,10 +395,10 @@ template T TMultiLinearInterp::operator()(const double* x) { int idx = set_index_arr(x); if(idx < 0) { return empty; } - + T sum; T term; - + unsigned int i_max = (1 << ndim); for(unsigned int i=0; i::operator()(const double* x) { } if(i == 0){ sum = term; } else { sum += term; } } - + return sum; } @@ -419,9 +425,9 @@ bool TMultiLinearInterp::operator()(const double* x, T& res) { //res = empty; return false; } - + T term; - + unsigned int i_max = (1 << ndim); for(unsigned int i=0; i::operator()(const double* x, T& res) { } if(i == 0){ res = term; } else { res += term; } } - + return true; } diff --git a/src/los_sampler.cpp b/src/los_sampler.cpp index 8047ac9..b0f5314 100644 --- a/src/los_sampler.cpp +++ b/src/los_sampler.cpp @@ -1,27 +1,27 @@ /* * los_sampler.cpp - * + * * Samples from posterior distribution of line-of-sight extinction * model, given a set of stellar posterior densities in DM, E(B-V). - * + * * This file is part of bayestar. * Copyright 2012 Gregory Green - * + * * Bayestar is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. - * + * */ #include "los_sampler.h" @@ -32,71 +32,71 @@ */ void test_extinction_profiles(TLOSMCMCParams ¶ms) { - bool exit = false; - - while(!exit) { - std::string response; - std::string yn; - - std::cout << std::endl << "Cloud ('c') or Piecewise-linear ('p') model ('-' to exit)? "; - std::cin >> response; - - if(response == "c") { - double dist, depth; - std::cout << "Cloud distance (DM): "; - std::cin >> dist; - std::cout << "Cloud depth (mags): "; - std::cin >> depth; - - double x[2]; - x[0] = dist; - x[1] = log(depth); - - double lnp = lnp_los_extinction_clouds(&(x[0]), 2, params); - - std::cout << "ln(p) = " << lnp << std::endl; - - std::cout << "Show more information (y/n)? "; - std::cin >> yn; - - if(yn == "y") { - // Compute line integrals through probability surfaces - double *line_int = params.get_line_int(0); - los_integral_clouds(*(params.img_stack), params.subpixel.data(), line_int, &(x[0]), &(x[1]), 1); - - - std::cout << " # ln(p) p_0/Z" << std::endl; - - double lnp_soft; - double ln_L = 0.; - - for(size_t i=0; iN_images; i++) { - if(line_int[i] > params.p0_over_Z[i]) { - lnp_soft = log(line_int[i]) + log(1. + params.p0_over_Z[i] / line_int[i]); - } else { - lnp_soft = params.ln_p0_over_Z[i] + log(1. + line_int[i] * params.inv_p0_over_Z[i]); - } - - ln_L += lnp_soft; - - std::cout << " " << i << ": " << log(line_int[i]) << " " << params.ln_p0_over_Z[i] << " " << lnp_soft << std::endl; - } - - std::cout << std::endl; - std::cout << "ln(L) = " << ln_L << std::endl; - std::cout << "ln(prior) = " << lnp - ln_L << std::endl; - } - - } else if(response == "p") { - std::cout << "Not yet implemented."; - - } else if(response == "-") { - exit = true; - - } else { - std::cout << "Invalid option: '" << response << "'" << std::endl; - } - } + bool exit = false; + + while(!exit) { + std::string response; + std::string yn; + + std::cout << std::endl << "Cloud ('c') or Piecewise-linear ('p') model ('-' to exit)? "; + std::cin >> response; + + if(response == "c") { + double dist, depth; + std::cout << "Cloud distance (DM): "; + std::cin >> dist; + std::cout << "Cloud depth (mags): "; + std::cin >> depth; + + double x[2]; + x[0] = dist; + x[1] = log(depth); + + double lnp = lnp_los_extinction_clouds(&(x[0]), 2, params); + + std::cout << "ln(p) = " << lnp << std::endl; + + std::cout << "Show more information (y/n)? "; + std::cin >> yn; + + if(yn == "y") { + // Compute line integrals through probability surfaces + double *line_int = params.get_line_int(0); + los_integral_clouds(*(params.img_stack), params.subpixel.data(), line_int, &(x[0]), &(x[1]), 1); + + + std::cout << " # ln(p) p_0/Z" << std::endl; + + double lnp_soft; + double ln_L = 0.; + + for(size_t i=0; iN_images; i++) { + if(line_int[i] > params.p0_over_Z[i]) { + lnp_soft = log(line_int[i]) + log(1. + params.p0_over_Z[i] / line_int[i]); + } else { + lnp_soft = params.ln_p0_over_Z[i] + log(1. + line_int[i] * params.inv_p0_over_Z[i]); + } + + ln_L += lnp_soft; + + std::cout << " " << i << ": " << log(line_int[i]) << " " << params.ln_p0_over_Z[i] << " " << lnp_soft << std::endl; + } + + std::cout << std::endl; + std::cout << "ln(L) = " << ln_L << std::endl; + std::cout << "ln(prior) = " << lnp - ln_L << std::endl; + } + + } else if(response == "p") { + std::cout << "Not yet implemented."; + + } else if(response == "-") { + exit = true; + + } else { + std::cout << "Invalid option: '" << response << "'" << std::endl; + } + } } @@ -108,320 +108,326 @@ void test_extinction_profiles(TLOSMCMCParams ¶ms) { void sample_los_extinction_clouds(const std::string& out_fname, const std::string& group_name, TMCMCOptions &options, TLOSMCMCParams ¶ms, unsigned int N_clouds, int verbosity) { - timespec t_start, t_write, t_end; - clock_gettime(CLOCK_MONOTONIC, &t_start); - - /*double x[] = {8., 4., -0.693, -1.61}; - gsl_rng *r; - seed_gsl_rng(&r); - //gen_rand_los_extinction_clouds(&(x[0]), 4, r, params); - double lnp_tmp = lnp_los_extinction_clouds(&(x[0]), 4, params); - std::cout << lnp_tmp << std::endl; - gsl_rng_free(r);*/ - - if(verbosity >= 2) { - std::cout << "subpixel: " << std::endl; - for(size_t i=0; i GR_transf; - TLOSCloudTransform transf(ndim); - double GR_threshold = 1.25; - - TAffineSampler::pdf_t f_pdf = &lnp_los_extinction_clouds; - TAffineSampler::rand_state_t f_rand_state = &gen_rand_los_extinction_clouds; - - if(verbosity >= 1) { - std::cout << std::endl; - std::cout << "Discrete cloud l.o.s. model" << std::endl; - std::cout << "====================================" << std::endl; - } - - //std::cerr << "# Setting up sampler" << std::endl; - TParallelAffineSampler sampler(f_pdf, f_rand_state, ndim, N_samplers*ndim, params, logger, N_runs); - sampler.set_sigma_min(1.e-5); - sampler.set_scale(2.); - sampler.set_replacement_bandwidth(0.35); - - // Burn-in - if(verbosity >= 1) { - std::cout << "# Burn-in ..." << std::endl; - } - sampler.step(int(N_steps*25./100.), false, 0., 0.); - sampler.step(int(N_steps*20./100.), false, 0., options.p_replacement); - sampler.step(int(N_steps*20./100.), false, 0., 0.85, 0.); - sampler.step(int(N_steps*20./100.), false, 0., options.p_replacement); - sampler.tune_stretch(5, 0.40); - sampler.step(int(N_steps*20./100.), false, 0., 0.85); - if(verbosity >= 2) { sampler.print_stats(); } - sampler.clear(); - - // Main sampling phase - if(verbosity >= 1) { - std::cout << "# Main run ..." << std::endl; - } - bool converged = false; - size_t attempt; - for(attempt = 0; (attempt < max_attempts) && (!converged); attempt++) { - if(verbosity >= 2) { - std::cout << std::endl; - std::cout << "scale: ("; - std::cout << std::setprecision(2); - for(int k=0; kget_scale() << ((k == sampler.get_N_samplers() - 1) ? "" : ", "); - } - } - sampler.tune_stretch(8, 0.40); - if(verbosity >= 2) { - std::cout << ") -> ("; - for(int k=0; kget_scale() << ((k == sampler.get_N_samplers() - 1) ? "" : ", "); - } - std::cout << ")" << std::endl; - } - - sampler.step((1<= 2) { - std::cout << std::endl << "Transformed G-R Diagnostic:"; - for(unsigned int k=0; k GR_threshold) { - converged = false; - if(attempt != max_attempts-1) { - if(verbosity >= 2) { - sampler.print_stats(); - } - - if(verbosity >= 1) { - std::cerr << "# Extending run ..." << std::endl; - } - - sampler.step(int(N_steps*1./5.), false, 0., 1.); - sampler.clear(); - //logger.clear(); - } - break; - } - } - } - - clock_gettime(CLOCK_MONOTONIC, &t_write); - - //std::stringstream group_name; - //group_name << "/pixel " << healpix_index; - //group_name << "/los clouds"; - //chain.save(out_fname, group_name.str(), 0, "Delta mu, Delta E(B-V)", 3, 100, converged); - - std::stringstream group_name_full; - group_name_full << "/" << group_name; - TChain chain = sampler.get_chain(); - - TChainWriteBuffer writeBuffer(ndim, 100, 1); - writeBuffer.add(chain, converged, std::numeric_limits::quiet_NaN(), GR_transf.data()); - writeBuffer.write(out_fname, group_name_full.str(), "clouds"); - - clock_gettime(CLOCK_MONOTONIC, &t_end); - - if(verbosity >= 2) { sampler.print_stats(); } - - if(verbosity >= 1) { - std::cout << std::endl; - - if(!converged) { - std::cout << "# Failed to converge." << std::endl; - } - - std::cout << "# Number of steps: " << (1<<(attempt-1))*N_steps << std::endl; - std::cout << "# Time elapsed: " << std::setprecision(2) << (t_end.tv_sec - t_start.tv_sec) + 1.e-9*(t_end.tv_nsec - t_start.tv_nsec) << " s" << std::endl; - std::cout << "# Sample time: " << std::setprecision(2) << (t_write.tv_sec - t_start.tv_sec) + 1.e-9*(t_write.tv_nsec - t_start.tv_nsec) << " s" << std::endl; - std::cout << "# Write time: " << std::setprecision(2) << (t_end.tv_sec - t_write.tv_sec) + 1.e-9*(t_end.tv_nsec - t_write.tv_nsec) << " s" << std::endl << std::endl; - } -} - -void los_integral_clouds(TImgStack &img_stack, const double *const subpixel, double *const ret, const double *const Delta_mu, - const double *const logDelta_EBV, unsigned int N_clouds) { - int x = 0; - int x_next = ceil((Delta_mu[0] - img_stack.rect->min[1]) / img_stack.rect->dx[1]); - - float y_0 = -img_stack.rect->min[0] / img_stack.rect->dx[0]; - float y = 0.; - int y_max = img_stack.rect->N_bins[0]; - float y_ceil, y_floor, dy, y_scaled; - int y_ceil_int, y_floor_int; - - for(size_t i=0; iN_bins[1]; - } else if(i != 0) { - x_next += ceil(Delta_mu[i] / img_stack.rect->dx[1]); - } - - if(x_next > img_stack.rect->N_bins[1]) { - x_next = img_stack.rect->N_bins[1]; - } else if(x_next < 0) { - x_next = 0; - } - - if(i != 0) { - y += exp(logDelta_EBV[i-1]) / img_stack.rect->dx[0]; - } - - int x_start = x; - for(int k=0; k= y_max) { std::cout << "!! y_ceil_int >= y_max !!" << std::endl; break; } - //if(y_floor_int < 0) { std::cout << "!! y_floor_int < 0 !!" << std::endl; break; } - - for(x = x_start; xat(y_floor_int, x) - + (y_scaled - y_floor) * img_stack.img[k]->at(y_ceil_int, x); - } - } - } + timespec t_start, t_write, t_end; + clock_gettime(CLOCK_MONOTONIC, &t_start); + + /*double x[] = {8., 4., -0.693, -1.61}; + gsl_rng *r; + seed_gsl_rng(&r); + //gen_rand_los_extinction_clouds(&(x[0]), 4, r, params); + double lnp_tmp = lnp_los_extinction_clouds(&(x[0]), 4, params); + std::cout << lnp_tmp << std::endl; + gsl_rng_free(r);*/ + + if(verbosity >= 2) { + std::cout << "subpixel: " << std::endl; + for(size_t i=0; i GR_transf; + TLOSCloudTransform transf(ndim); + double GR_threshold = 1.25; + + TAffineSampler::pdf_t f_pdf = &lnp_los_extinction_clouds; + TAffineSampler::rand_state_t f_rand_state = &gen_rand_los_extinction_clouds; + + if(verbosity >= 1) { + std::cout << std::endl; + std::cout << "Discrete cloud l.o.s. model" << std::endl; + std::cout << "====================================" << std::endl; + } + + //std::cerr << "# Setting up sampler" << std::endl; + TParallelAffineSampler sampler(f_pdf, f_rand_state, ndim, N_samplers*ndim, params, logger, N_runs); + sampler.set_sigma_min(1.e-5); + sampler.set_scale(2.); + sampler.set_replacement_bandwidth(0.35); + + // Burn-in + if(verbosity >= 1) { + std::cout << "# Burn-in ..." << std::endl; + } + sampler.step(int(N_steps*25./100.), false, 0., 0.); + sampler.step(int(N_steps*20./100.), false, 0., options.p_replacement); + sampler.step(int(N_steps*20./100.), false, 0., 0.85, 0.); + sampler.step(int(N_steps*20./100.), false, 0., options.p_replacement); + sampler.tune_stretch(5, 0.40); + sampler.step(int(N_steps*20./100.), false, 0., 0.85); + if(verbosity >= 2) { sampler.print_stats(); } + sampler.clear(); + + // Main sampling phase + if(verbosity >= 1) { + std::cout << "# Main run ..." << std::endl; + } + bool converged = false; + size_t attempt; + for(attempt = 0; (attempt < max_attempts) && (!converged); attempt++) { + if(verbosity >= 2) { + std::cout << std::endl; + std::cout << "scale: ("; + std::cout << std::setprecision(2); + for(int k=0; kget_scale() << ((k == sampler.get_N_samplers() - 1) ? "" : ", "); + } + } + sampler.tune_stretch(8, 0.40); + if(verbosity >= 2) { + std::cout << ") -> ("; + for(int k=0; kget_scale() << ((k == sampler.get_N_samplers() - 1) ? "" : ", "); + } + std::cout << ")" << std::endl; + } + + sampler.step((1<= 2) { + std::cout << std::endl << "Transformed G-R Diagnostic:"; + for(unsigned int k=0; k GR_threshold) { + converged = false; + if(attempt != max_attempts-1) { + if(verbosity >= 2) { + sampler.print_stats(); + } + + if(verbosity >= 1) { + std::cerr << "# Extending run ..." << std::endl; + } + + sampler.step(int(N_steps*1./5.), false, 0., 1.); + sampler.clear(); + //logger.clear(); + } + break; + } + } + } + + clock_gettime(CLOCK_MONOTONIC, &t_write); + + //std::stringstream group_name; + //group_name << "/pixel " << healpix_index; + //group_name << "/los clouds"; + //chain.save(out_fname, group_name.str(), 0, "Delta mu, Delta E(B-V)", 3, 100, converged); + + std::stringstream group_name_full; + group_name_full << "/" << group_name; + TChain chain = sampler.get_chain(); + + TChainWriteBuffer writeBuffer(ndim, 100, 1); + writeBuffer.add(chain, converged, std::numeric_limits::quiet_NaN(), GR_transf.data()); + writeBuffer.write(out_fname, group_name_full.str(), "clouds"); + + clock_gettime(CLOCK_MONOTONIC, &t_end); + + if(verbosity >= 2) { sampler.print_stats(); } + + if(verbosity >= 1) { + std::cout << std::endl; + + if(!converged) { + std::cout << "# Failed to converge." << std::endl; + } + + std::cout << "# Number of steps: " << (1<<(attempt-1))*N_steps << std::endl; + std::cout << "# Time elapsed: " << std::setprecision(2) << (t_end.tv_sec - t_start.tv_sec) + 1.e-9*(t_end.tv_nsec - t_start.tv_nsec) << " s" << std::endl; + std::cout << "# Sample time: " << std::setprecision(2) << (t_write.tv_sec - t_start.tv_sec) + 1.e-9*(t_write.tv_nsec - t_start.tv_nsec) << " s" << std::endl; + std::cout << "# Write time: " << std::setprecision(2) << (t_end.tv_sec - t_write.tv_sec) + 1.e-9*(t_end.tv_nsec - t_write.tv_nsec) << " s" << std::endl << std::endl; + } +} + +void los_integral_clouds( + TImgStack &img_stack, + const double *const subpixel, + double *const ret, + const double *const Delta_mu, + const double *const logDelta_EBV, + unsigned int N_clouds) +{ + int x = 0; + int x_next = ceil((Delta_mu[0] - img_stack.rect->min[1]) / img_stack.rect->dx[1]); + + floating_t y_0 = -img_stack.rect->min[0] / img_stack.rect->dx[0]; + floating_t y = 0.; + int y_max = img_stack.rect->N_bins[0]; + floating_t y_ceil, y_floor, dy, y_scaled; + int y_ceil_int, y_floor_int; + + for(size_t i=0; iN_bins[1]; + } else if(i != 0) { + x_next += ceil(Delta_mu[i] / img_stack.rect->dx[1]); + } + + if(x_next > img_stack.rect->N_bins[1]) { + x_next = img_stack.rect->N_bins[1]; + } else if(x_next < 0) { + x_next = 0; + } + + if(i != 0) { + y += exp(logDelta_EBV[i-1]) / img_stack.rect->dx[0]; + } + + int x_start = x; + for(int k=0; k= y_max) { std::cout << "!! y_ceil_int >= y_max !!" << std::endl; break; } + //if(y_floor_int < 0) { std::cout << "!! y_floor_int < 0 !!" << std::endl; break; } + + for(x = x_start; xat(y_floor_int, x) + + (y_scaled - y_floor) * img_stack.img[k]->at(y_ceil_int, x); + } + } + } } double lnp_los_extinction_clouds(const double* x, unsigned int N, TLOSMCMCParams& params) { - int thread_num = omp_get_thread_num(); - - const size_t N_clouds = N / 2; - const double *Delta_mu = x; - const double *logDelta_EBV = x + N_clouds; - - double lnp = 0.; - - // Delta_mu must be positive - double mu_tot = 0.; - for(size_t i=0; irect->min[1]) { return neg_inf_replacement; } - //if(mu_tot >= params.img_stack->rect->max[1]) { return neg_inf_replacement; } - int mu_tot_idx = ceil((mu_tot * params.subpixel_max - params.img_stack->rect->min[1]) / params.img_stack->rect->dx[1]); - if(mu_tot_idx + 1 >= params.img_stack->rect->N_bins[1]) { return neg_inf_replacement; } - - const double bias = -5.; - const double sigma = 5.; - - double EBV_tot = 0.; - double tmp; - for(size_t i=0; i= params.img_stack->rect->max[0]) { return neg_inf_replacement; } - double EBV_tot_idx = ceil((EBV_tot * params.subpixel_max - params.img_stack->rect->min[0]) / params.img_stack->rect->dx[0]); - if(EBV_tot_idx + 1 >= params.img_stack->rect->N_bins[0]) { return neg_inf_replacement; } - - // Prior on total extinction - if((params.EBV_max > 0.) && (EBV_tot > params.EBV_max)) { - lnp -= (EBV_tot - params.EBV_max) * (EBV_tot - params.EBV_max) / (2. * 0.20 * 0.20 * params.EBV_max * params.EBV_max); - } - - // Repulsive force to keep clouds from collapsing into one - for(size_t i=1; iN_images; i++) { - /*if(line_int[i] < 1.e5*params.p0) { - line_int[i] += params.p0 * exp(-line_int[i]/params.p0); - } - lnp += log(line_int[i]);*/ - if(line_int[i] > params.p0_over_Z[i]) { - lnp_indiv = log(line_int[i]) + log(1. + params.p0_over_Z[i] / line_int[i]); - } else { - lnp_indiv = params.ln_p0_over_Z[i] + log(1. + line_int[i] * params.inv_p0_over_Z[i]); - } - - lnp += lnp_indiv; - } - - return lnp; + int thread_num = omp_get_thread_num(); + + const size_t N_clouds = N / 2; + const double *Delta_mu = x; + const double *logDelta_EBV = x + N_clouds; + + double lnp = 0.; + + // Delta_mu must be positive + double mu_tot = 0.; + for(size_t i=0; irect->min[1]) { return neg_inf_replacement; } + //if(mu_tot >= params.img_stack->rect->max[1]) { return neg_inf_replacement; } + int mu_tot_idx = ceil((mu_tot * params.subpixel_max - params.img_stack->rect->min[1]) / params.img_stack->rect->dx[1]); + if(mu_tot_idx + 1 >= params.img_stack->rect->N_bins[1]) { return neg_inf_replacement; } + + const double bias = -5.; + const double sigma = 5.; + + double EBV_tot = 0.; + double tmp; + for(size_t i=0; i= params.img_stack->rect->max[0]) { return neg_inf_replacement; } + double EBV_tot_idx = ceil((EBV_tot * params.subpixel_max - params.img_stack->rect->min[0]) / params.img_stack->rect->dx[0]); + if(EBV_tot_idx + 1 >= params.img_stack->rect->N_bins[0]) { return neg_inf_replacement; } + + // Prior on total extinction + if((params.EBV_max > 0.) && (EBV_tot > params.EBV_max)) { + lnp -= (EBV_tot - params.EBV_max) * (EBV_tot - params.EBV_max) / (2. * 0.20 * 0.20 * params.EBV_max * params.EBV_max); + } + + // Repulsive force to keep clouds from collapsing into one + for(size_t i=1; iN_images; i++) { + /*if(line_int[i] < 1.e5*params.p0) { + line_int[i] += params.p0 * exp(-line_int[i]/params.p0); + } + lnp += log(line_int[i]);*/ + if(line_int[i] > params.p0_over_Z[i]) { + lnp_indiv = log(line_int[i]) + log(1. + params.p0_over_Z[i] / line_int[i]); + } else { + lnp_indiv = params.ln_p0_over_Z[i] + log(1. + line_int[i] * params.inv_p0_over_Z[i]); + } + + lnp += lnp_indiv; + } + + return lnp; } void gen_rand_los_extinction_clouds(double *const x, unsigned int N, gsl_rng *r, TLOSMCMCParams ¶ms) { - double mu_floor = params.img_stack->rect->min[1]; - double mu_ceil = params.img_stack->rect->max[1]; - double EBV_ceil = params.img_stack->rect->max[0] / params.subpixel_max; - unsigned int N_clouds = N / 2; - - double logEBV_mean = log(1.5 * params.EBV_guess_max / params.subpixel_max / (double)N_clouds); - double mu_mean = (mu_ceil - mu_floor) / N_clouds; - double EBV_sum = 0.; - double mu_sum = mu_floor; - - double *Delta_mu = x; - double *logDelta_EBV = x + N_clouds; - - double log_mu_mean = log(0.5 * mu_mean); - for(size_t i=0; i= 0.95 * EBV_ceil) { - double factor = log(0.95 * EBV_ceil / EBV_sum); - for(size_t i=0; i= 0.95 * mu_ceil) { - double factor = 0.95 * mu_ceil / mu_sum; - for(size_t i=0; irect->min[1]; + double mu_ceil = params.img_stack->rect->max[1]; + double EBV_ceil = params.img_stack->rect->max[0] / params.subpixel_max; + unsigned int N_clouds = N / 2; + + double logEBV_mean = log(1.5 * params.EBV_guess_max / params.subpixel_max / (double)N_clouds); + double mu_mean = (mu_ceil - mu_floor) / N_clouds; + double EBV_sum = 0.; + double mu_sum = mu_floor; + + double *Delta_mu = x; + double *logDelta_EBV = x + N_clouds; + + double log_mu_mean = log(0.5 * mu_mean); + for(size_t i=0; i= 0.95 * EBV_ceil) { + double factor = log(0.95 * EBV_ceil / EBV_sum); + for(size_t i=0; i= 0.95 * mu_ceil) { + double factor = 0.95 * mu_ceil / mu_sum; + for(size_t i=0; i= 1) { - //std::cout << std::endl; - std::cout << "Piecewise-linear l.o.s. model" << std::endl; - std::cout << "====================================" << std::endl; - } - - if(verbosity >= 2) { - std::cout << "guess of EBV max = " << params.EBV_guess_max << std::endl; - } - - if(verbosity >= 1) { - std::cout << "# Generating Guess ..." << std::endl; - } - - //std::vector guess_time; - - /*for(int i=0; i<50; i++) { - timespec t_0, t_1; - double t_tmp; - - clock_gettime(CLOCK_MONOTONIC, &t_0); - - guess_EBV_profile(options, params); - - clock_gettime(CLOCK_MONOTONIC, &t_1); - - t_tmp = (t_1.tv_sec - t_0.tv_sec) + 1.e-9 * (t_1.tv_nsec - t_0.tv_nsec); - //guess_time.push_back(t_tmp); - - std::cerr << "Guess " << i << ": " << t_tmp << " s" << std::endl; - }*/ - - guess_EBV_profile(options, params, verbosity); - - - //monotonic_guess(img_stack, N_regions, params.EBV_prof_guess, options); - if(verbosity >= 2) { - for(size_t i=0; irect->max[1]; - double DM_min = params.img_stack->rect->min[1]; - double Delta_DM = (DM_max - DM_min) / (double)(params.N_regions); - unsigned int max_conv_idx = ceil((max_conv_mu - DM_min) / Delta_DM); - //std::cout << "max_conv_idx = " << max_conv_idx << std::endl; - - std::vector GR_transf; - TLOSTransform transf(ndim); - double GR_threshold = 1.25; - - TAffineSampler::pdf_t f_pdf = &lnp_los_extinction; - TAffineSampler::rand_state_t f_rand_state = &gen_rand_los_extinction_from_guess; - TAffineSampler::reversible_step_t switch_step = &switch_adjacent_log_Delta_EBVs; - TAffineSampler::reversible_step_t mix_step = &mix_log_Delta_EBVs; - TAffineSampler::reversible_step_t move_one_step = &step_one_Delta_EBV; - - TParallelAffineSampler sampler(f_pdf, f_rand_state, ndim, N_samplers*ndim, params, logger, N_runs); - - // Burn-in - if(verbosity >= 1) { std::cout << "# Burn-in ..." << std::endl; } - - // Round 1 (5/20) - unsigned int base_N_steps = ceil((double)N_steps * 1./20.); - - sampler.set_sigma_min(1.e-5); - sampler.set_scale(1.1); - sampler.set_replacement_bandwidth(0.25); - sampler.set_MH_bandwidth(0.15); - - sampler.tune_MH(8, 0.25); - sampler.step_MH(base_N_steps, false); - - sampler.tune_MH(8, 0.25); - sampler.step_MH(base_N_steps, false); - - if(verbosity >= 2) { - std::cout << "scale: ("; - for(int k=0; kget_scale() << ((k == sampler.get_N_samplers() - 1) ? "" : ", "); - } - } - sampler.tune_stretch(5, 0.30); - if(verbosity >= 2) { - std::cout << ") -> ("; - for(int k=0; kget_scale() << ((k == sampler.get_N_samplers() - 1) ? "" : ", "); - } - std::cout << ")" << std::endl; - } - - sampler.step(2*base_N_steps, false, 0., options.p_replacement); - sampler.step(base_N_steps, false, 0., 1., true, true); - - if(verbosity >= 2) { - std::cout << "Round 1 diagnostics:" << std::endl; - sampler.print_diagnostics(); - std::cout << std::endl; - } - - // Round 2 (5/20) - - sampler.set_replacement_accept_bias(1.e-2); - - if(verbosity >= 2) { - std::cout << "scale: ("; - for(int k=0; kget_scale() << ((k == sampler.get_N_samplers() - 1) ? "" : ", "); - } - } - sampler.tune_stretch(8, 0.30); - if(verbosity >= 2) { - std::cout << ") -> ("; - for(int k=0; kget_scale() << ((k == sampler.get_N_samplers() - 1) ? "" : ", "); - } - std::cout << ")" << std::endl; - } - - sampler.step(int(N_steps*2./20.), false, 0., options.p_replacement); - - sampler.step_custom_reversible(base_N_steps, switch_step, false); - sampler.step_custom_reversible(base_N_steps, mix_step, false); - sampler.step_custom_reversible(base_N_steps, move_one_step, false); - - //sampler.step(2*base_N_steps, false, 0., options.p_replacement); - sampler.step(base_N_steps, false, 0., 1., true, true); - - if(verbosity >= 2) { - std::cout << "Round 2 diagnostics:" << std::endl; - sampler.print_diagnostics(); - std::cout << std::endl; - } - - // Round 3 (5/20) - - if(verbosity >= 2) { - std::cout << "scale: ("; - for(int k=0; kget_scale() << ((k == sampler.get_N_samplers() - 1) ? "" : ", "); - } - } - sampler.tune_stretch(8, 0.30); - if(verbosity >= 2) { - std::cout << ") -> ("; - for(int k=0; kget_scale() << ((k == sampler.get_N_samplers() - 1) ? "" : ", "); - } - std::cout << ")" << std::endl; - } - - //sampler.step_MH(int(N_steps*1./20.), false); - sampler.step(2*base_N_steps, false, 0., options.p_replacement); - - sampler.step_custom_reversible(base_N_steps, switch_step, false); - sampler.step_custom_reversible(base_N_steps, mix_step, false); - sampler.step_custom_reversible(base_N_steps, move_one_step, false); - - if(verbosity >= 2) { - std::cout << "Round 3 diagnostics:" << std::endl; - sampler.print_diagnostics(); - std::cout << std::endl; - } - - // Round 4 (5/20) - sampler.set_replacement_accept_bias(0.); - - //sampler.tune_MH(8, 0.25); - if(verbosity >= 2) { - std::cout << "scale: ("; - for(int k=0; kget_scale() << ((k == sampler.get_N_samplers() - 1) ? "" : ", "); - } - } - sampler.tune_stretch(8, 0.30); - if(verbosity >= 2) { - std::cout << ") -> ("; - for(int k=0; kget_scale() << ((k == sampler.get_N_samplers() - 1) ? "" : ", "); - } - std::cout << ")" << std::endl; - } - - //sampler.step_MH(int(N_steps*2./15.), false); - sampler.step(2*base_N_steps, false, 0., options.p_replacement); - - sampler.step_custom_reversible(base_N_steps, switch_step, false); - sampler.step_custom_reversible(base_N_steps, mix_step, false); - sampler.step_custom_reversible(base_N_steps, move_one_step, false); - - if(verbosity >= 2) { - std::cout << "Round 4 diagnostics:" << std::endl; - sampler.print_diagnostics(); - std::cout << std::endl; - } - - sampler.clear(); - - // Main sampling phase (15/15) - if(verbosity >= 1) { std::cout << "# Main run ..." << std::endl; } - bool converged = false; - size_t attempt; - for(attempt = 0; (attempt < max_attempts) && (!converged); attempt++) { - /*if(verbosity >= 2) { - std::cout << std::endl; - std::cout << "M-H bandwidth: ("; - std::cout << std::setprecision(3); - for(int k=0; kget_MH_bandwidth() << ((k == sampler.get_N_samplers() - 1) ? "" : ", "); - } - } - sampler.tune_MH(10, 0.25); - if(verbosity >= 2) { - std::cout << ") -> ("; - for(int k=0; kget_MH_bandwidth() << ((k == sampler.get_N_samplers() - 1) ? "" : ", "); - } - std::cout << ")" << std::endl; - }*/ - - if(verbosity >= 2) { - std::cout << "scale: ("; - for(int k=0; kget_scale() << ((k == sampler.get_N_samplers() - 1) ? "" : ", "); - } - } - //sampler.tune_stretch(8, 0.30); - if(verbosity >= 2) { - std::cout << ") -> ("; - for(int k=0; kget_scale() << ((k == sampler.get_N_samplers() - 1) ? "" : ", "); - } - std::cout << ")" << std::endl; - } - - base_N_steps = ceil((double)((1<= 2) { - std::cout << std::endl << "Transformed G-R Diagnostic:"; - for(unsigned int k=0; k GR_threshold) { - converged = false; - if(attempt != max_attempts-1) { - if(verbosity >= 2) { - sampler.print_stats(); - } - - if(verbosity >= 1) { - std::cout << "# Extending run ..." << std::endl; - } - - sampler.step(3*base_N_steps, false, 0., 1.); - sampler.step_custom_reversible(base_N_steps, switch_step, true); - - sampler.clear(); - //logger.clear(); - } - break; - } - } - } - - clock_gettime(CLOCK_MONOTONIC, &t_write); - - std::stringstream group_name_full; - group_name_full << "/" << group_name; - TChain chain = sampler.get_chain(); - - TChainWriteBuffer writeBuffer(ndim, 500, 1); - writeBuffer.add(chain, converged, std::numeric_limits::quiet_NaN(), GR_transf.data()); - writeBuffer.write(out_fname, group_name_full.str(), "los"); - - std::stringstream los_group_name; - los_group_name << group_name_full.str() << "/los"; - H5Utils::add_watermark(out_fname, los_group_name.str(), "DM_min", params.img_stack->rect->min[1]); - H5Utils::add_watermark(out_fname, los_group_name.str(), "DM_max", params.img_stack->rect->max[1]); - - clock_gettime(CLOCK_MONOTONIC, &t_end); - - /* - std::vector best_dbl; - std::vector best; - double * line_int_best = new double[params.img_stack->N_images]; - - std::cout << "get_best" << std::endl; - chain.get_best(best_dbl); - - std::cout << "exp" << std::endl; - double tmp_tot = 0; - for(int i=0; iN_images; i++) { - if(line_int_best[i] > params.p0_over_Z[i]) { - lnp_soft = log(line_int_best[i]) + log(1. + params.p0_over_Z[i] / line_int_best[i]); - } else { - lnp_soft = params.ln_p0_over_Z[i] + log(1. + line_int_best[i] * params.inv_p0_over_Z[i]); - } - - ln_L += lnp_soft; - - std::cout << " " << i << ": " << log(line_int_best[i]) << " " << params.ln_p0_over_Z[i] << " " << lnp_soft << std::endl; - } - - std::cout << std::endl; - std::cout << "ln(L) = " << ln_L << std::endl; - std::cout << std::endl; - - delete[] line_int_best; - */ - - if(verbosity >= 2) { sampler.print_stats(); } - - if(verbosity >= 1) { - std::cout << std::endl; - - if(!converged) { - std::cout << "# Failed to converge." << std::endl; - } - - std::cout << "# Number of steps: " << (1<<(attempt-1))*N_steps << std::endl; - std::cout << "# Time elapsed: " << std::setprecision(2) << (t_end.tv_sec - t_start.tv_sec) + 1.e-9*(t_end.tv_nsec - t_start.tv_nsec) << " s" << std::endl; - std::cout << "# Sample time: " << std::setprecision(2) << (t_write.tv_sec - t_start.tv_sec) + 1.e-9*(t_write.tv_nsec - t_start.tv_nsec) << " s" << std::endl; - std::cout << "# Write time: " << std::setprecision(2) << (t_end.tv_sec - t_write.tv_sec) + 1.e-9*(t_end.tv_nsec - t_write.tv_nsec) << " s" << std::endl << std::endl; - } + timespec t_start, t_write, t_end; + clock_gettime(CLOCK_MONOTONIC, &t_start); + + if(verbosity >= 1) { + //std::cout << std::endl; + std::cout << "Piecewise-linear l.o.s. model" << std::endl; + std::cout << "====================================" << std::endl; + } + + if(verbosity >= 2) { + std::cout << "guess of EBV max = " << params.EBV_guess_max << std::endl; + } + + if(verbosity >= 1) { + std::cout << "# Generating Guess ..." << std::endl; + } + + //std::vector guess_time; + + /*for(int i=0; i<50; i++) { + timespec t_0, t_1; + double t_tmp; + + clock_gettime(CLOCK_MONOTONIC, &t_0); + + guess_EBV_profile(options, params); + + clock_gettime(CLOCK_MONOTONIC, &t_1); + + t_tmp = (t_1.tv_sec - t_0.tv_sec) + 1.e-9 * (t_1.tv_nsec - t_0.tv_nsec); + //guess_time.push_back(t_tmp); + + std::cerr << "Guess " << i << ": " << t_tmp << " s" << std::endl; + }*/ + + guess_EBV_profile(options, params, verbosity); + + + //monotonic_guess(img_stack, N_regions, params.EBV_prof_guess, options); + if(verbosity >= 2) { + for(size_t i=0; irect->max[1]; + double DM_min = params.img_stack->rect->min[1]; + double Delta_DM = (DM_max - DM_min) / (double)(params.N_regions); + unsigned int max_conv_idx = ceil((max_conv_mu - DM_min) / Delta_DM); + //std::cout << "max_conv_idx = " << max_conv_idx << std::endl; + + std::vector GR_transf; + TLOSTransform transf(ndim); + double GR_threshold = 1.25; + + TAffineSampler::pdf_t f_pdf = &lnp_los_extinction; + TAffineSampler::rand_state_t f_rand_state = &gen_rand_los_extinction_from_guess; + TAffineSampler::reversible_step_t switch_step = &switch_adjacent_log_Delta_EBVs; + TAffineSampler::reversible_step_t mix_step = &mix_log_Delta_EBVs; + TAffineSampler::reversible_step_t move_one_step = &step_one_Delta_EBV; + + TParallelAffineSampler sampler(f_pdf, f_rand_state, ndim, N_samplers*ndim, params, logger, N_runs); + + // Burn-in + if(verbosity >= 1) { std::cout << "# Burn-in ..." << std::endl; } + + // Round 1 (5/20) + unsigned int base_N_steps = ceil((double)N_steps * 1./20.); + + sampler.set_sigma_min(1.e-5); + sampler.set_scale(1.1); + sampler.set_replacement_bandwidth(0.25); + sampler.set_MH_bandwidth(0.15); + + sampler.tune_MH(8, 0.25); + sampler.step_MH(base_N_steps, false); + + sampler.tune_MH(8, 0.25); + sampler.step_MH(base_N_steps, false); + + if(verbosity >= 2) { + std::cout << "scale: ("; + for(int k=0; kget_scale() << ((k == sampler.get_N_samplers() - 1) ? "" : ", "); + } + } + sampler.tune_stretch(5, 0.30); + if(verbosity >= 2) { + std::cout << ") -> ("; + for(int k=0; kget_scale() << ((k == sampler.get_N_samplers() - 1) ? "" : ", "); + } + std::cout << ")" << std::endl; + } + + sampler.step(2*base_N_steps, false, 0., options.p_replacement); + sampler.step(base_N_steps, false, 0., 1., true, true); + + if(verbosity >= 2) { + std::cout << "Round 1 diagnostics:" << std::endl; + sampler.print_diagnostics(); + std::cout << std::endl; + } + + // Round 2 (5/20) + + sampler.set_replacement_accept_bias(1.e-2); + + if(verbosity >= 2) { + std::cout << "scale: ("; + for(int k=0; kget_scale() << ((k == sampler.get_N_samplers() - 1) ? "" : ", "); + } + } + sampler.tune_stretch(8, 0.30); + if(verbosity >= 2) { + std::cout << ") -> ("; + for(int k=0; kget_scale() << ((k == sampler.get_N_samplers() - 1) ? "" : ", "); + } + std::cout << ")" << std::endl; + } + + sampler.step(int(N_steps*2./20.), false, 0., options.p_replacement); + + sampler.step_custom_reversible(base_N_steps, switch_step, false); + sampler.step_custom_reversible(base_N_steps, mix_step, false); + sampler.step_custom_reversible(base_N_steps, move_one_step, false); + + //sampler.step(2*base_N_steps, false, 0., options.p_replacement); + sampler.step(base_N_steps, false, 0., 1., true, true); + + if(verbosity >= 2) { + std::cout << "Round 2 diagnostics:" << std::endl; + sampler.print_diagnostics(); + std::cout << std::endl; + } + + // Round 3 (5/20) + + if(verbosity >= 2) { + std::cout << "scale: ("; + for(int k=0; kget_scale() << ((k == sampler.get_N_samplers() - 1) ? "" : ", "); + } + } + sampler.tune_stretch(8, 0.30); + if(verbosity >= 2) { + std::cout << ") -> ("; + for(int k=0; kget_scale() << ((k == sampler.get_N_samplers() - 1) ? "" : ", "); + } + std::cout << ")" << std::endl; + } + + //sampler.step_MH(int(N_steps*1./20.), false); + sampler.step(2*base_N_steps, false, 0., options.p_replacement); + + sampler.step_custom_reversible(base_N_steps, switch_step, false); + sampler.step_custom_reversible(base_N_steps, mix_step, false); + sampler.step_custom_reversible(base_N_steps, move_one_step, false); + + if(verbosity >= 2) { + std::cout << "Round 3 diagnostics:" << std::endl; + sampler.print_diagnostics(); + std::cout << std::endl; + } + + // Round 4 (5/20) + sampler.set_replacement_accept_bias(0.); + + //sampler.tune_MH(8, 0.25); + if(verbosity >= 2) { + std::cout << "scale: ("; + for(int k=0; kget_scale() << ((k == sampler.get_N_samplers() - 1) ? "" : ", "); + } + } + sampler.tune_stretch(8, 0.30); + if(verbosity >= 2) { + std::cout << ") -> ("; + for(int k=0; kget_scale() << ((k == sampler.get_N_samplers() - 1) ? "" : ", "); + } + std::cout << ")" << std::endl; + } + + //sampler.step_MH(int(N_steps*2./15.), false); + sampler.step(2*base_N_steps, false, 0., options.p_replacement); + + sampler.step_custom_reversible(2*base_N_steps, switch_step, false); + //sampler.step_custom_reversible(base_N_steps, mix_step, false); + sampler.step_custom_reversible(base_N_steps, move_one_step, false); + + if(verbosity >= 2) { + std::cout << "Round 4 diagnostics:" << std::endl; + sampler.print_diagnostics(); + std::cout << std::endl; + } + + sampler.clear(); + + // Main sampling phase (15/15) + if(verbosity >= 1) { std::cout << "# Main run ..." << std::endl; } + bool converged = false; + size_t attempt; + for(attempt = 0; (attempt < max_attempts) && (!converged); attempt++) { + /*if(verbosity >= 2) { + std::cout << std::endl; + std::cout << "M-H bandwidth: ("; + std::cout << std::setprecision(3); + for(int k=0; kget_MH_bandwidth() << ((k == sampler.get_N_samplers() - 1) ? "" : ", "); + } + } + sampler.tune_MH(10, 0.25); + if(verbosity >= 2) { + std::cout << ") -> ("; + for(int k=0; kget_MH_bandwidth() << ((k == sampler.get_N_samplers() - 1) ? "" : ", "); + } + std::cout << ")" << std::endl; + }*/ + + if(verbosity >= 2) { + std::cout << "scale: ("; + for(int k=0; kget_scale() << ((k == sampler.get_N_samplers() - 1) ? "" : ", "); + } + } + //sampler.tune_stretch(8, 0.30); + if(verbosity >= 2) { + std::cout << ") -> ("; + for(int k=0; kget_scale() << ((k == sampler.get_N_samplers() - 1) ? "" : ", "); + } + std::cout << ")" << std::endl; + } + + base_N_steps = ceil((double)((1<= 2) { + std::cout << std::endl << "Transformed G-R Diagnostic:"; + for(unsigned int k=0; k GR_threshold) { + converged = false; + if(attempt != max_attempts-1) { + if(verbosity >= 2) { + sampler.print_stats(); + } + + if(verbosity >= 1) { + std::cout << "# Extending run ..." << std::endl; + } + + sampler.step(3*base_N_steps, false, 0., 1.); + sampler.step_custom_reversible(base_N_steps, switch_step, true); + + sampler.clear(); + //logger.clear(); + } + break; + } + } + } + + clock_gettime(CLOCK_MONOTONIC, &t_write); + + std::stringstream group_name_full; + group_name_full << "/" << group_name; + TChain chain = sampler.get_chain(); + + TChainWriteBuffer writeBuffer(ndim, 500, 1); + writeBuffer.add(chain, converged, std::numeric_limits::quiet_NaN(), GR_transf.data()); + writeBuffer.write(out_fname, group_name_full.str(), "los"); + + std::stringstream los_group_name; + los_group_name << group_name_full.str() << "/los"; + H5Utils::add_watermark(out_fname, los_group_name.str(), "DM_min", params.img_stack->rect->min[1]); + H5Utils::add_watermark(out_fname, los_group_name.str(), "DM_max", params.img_stack->rect->max[1]); + + clock_gettime(CLOCK_MONOTONIC, &t_end); + + /* + std::vector best_dbl; + std::vector best; + double * line_int_best = new double[params.img_stack->N_images]; + + std::cout << "get_best" << std::endl; + chain.get_best(best_dbl); + + std::cout << "exp" << std::endl; + double tmp_tot = 0; + for(int i=0; iN_images; i++) { + if(line_int_best[i] > params.p0_over_Z[i]) { + lnp_soft = log(line_int_best[i]) + log(1. + params.p0_over_Z[i] / line_int_best[i]); + } else { + lnp_soft = params.ln_p0_over_Z[i] + log(1. + line_int_best[i] * params.inv_p0_over_Z[i]); + } + + ln_L += lnp_soft; + + std::cout << " " << i << ": " << log(line_int_best[i]) << " " << params.ln_p0_over_Z[i] << " " << lnp_soft << std::endl; + } + + std::cout << std::endl; + std::cout << "ln(L) = " << ln_L << std::endl; + std::cout << std::endl; + + delete[] line_int_best; + */ + + if(verbosity >= 2) { sampler.print_stats(); } + + if(verbosity >= 1) { + std::cout << std::endl; + + if(!converged) { + std::cout << "# Failed to converge." << std::endl; + } + + std::cout << "# Number of steps: " << (1<<(attempt-1))*N_steps << std::endl; + std::cout << "# Time elapsed: " << std::setprecision(2) << (t_end.tv_sec - t_start.tv_sec) + 1.e-9*(t_end.tv_nsec - t_start.tv_nsec) << " s" << std::endl; + std::cout << "# Sample time: " << std::setprecision(2) << (t_write.tv_sec - t_start.tv_sec) + 1.e-9*(t_write.tv_nsec - t_start.tv_nsec) << " s" << std::endl; + std::cout << "# Write time: " << std::setprecision(2) << (t_end.tv_sec - t_write.tv_sec) + 1.e-9*(t_end.tv_nsec - t_write.tv_nsec) << " s" << std::endl << std::endl; + } } void los_integral(TImgStack &img_stack, const double *const subpixel, double *const ret, const float *const Delta_EBV, unsigned int N_regions) { - assert(img_stack.rect->N_bins[1] % N_regions == 0); - - const int subsampling = 1; - const int N_pix_per_bin = img_stack.rect->N_bins[1] / N_regions; - const float N_samples = subsampling * N_pix_per_bin; - const int y_max = img_stack.rect->N_bins[0]; - - int x; - - float Delta_y_0 = Delta_EBV[0] / img_stack.rect->dx[0]; - const float y_0 = -img_stack.rect->min[0] / img_stack.rect->dx[0]; - float y, dy; - - // Integer arithmetic is the poor man's fixed-point math - typedef uint32_t fixed_point_t; - const int base_2_prec = 18; // unsigned Q14.18 format - - const fixed_point_t prec_factor_int = (1 << base_2_prec); - const float prec_factor = (float)prec_factor_int; - - fixed_point_t y_int, dy_int; - fixed_point_t y_ceil, y_floor; - fixed_point_t diff; - - // Pre-computed multiplicative factors - float dy_mult_factor = 1. / N_samples / img_stack.rect->dx[0]; - float ret_mult_factor = 1. / (float)subsampling / prec_factor; - - float tmp_ret, tmp_subpixel; - cv::Mat *img; - - // For each image - for(int k=0; k> base_2_prec); - diff = y_int - (y_floor << base_2_prec); - - tmp_ret += (prec_factor_int - diff) * img->at(y_floor, x) - + diff * img->at(y_floor+1, x); - - /* - // 1 - y_int += dy_int; - y_floor = (y_int >> base_2_prec); - diff = y_int - (y_floor << base_2_prec); - - tmp_ret += diff * img->at(y_floor, x) - + (prec_factor_int - diff) * img->at(y_floor+1, x); - - // 2 - y_int += dy_int; - y_floor = (y_int >> base_2_prec); - diff = y_int - (y_floor << base_2_prec); - - tmp_ret += diff * img->at(y_floor, x) - + (prec_factor_int - diff) * img->at(y_floor+1, x); - */ - } - } - - ret[k] = tmp_ret * ret_mult_factor; - } + assert(img_stack.rect->N_bins[1] % N_regions == 0); + + const int subsampling = 1; + const int N_pix_per_bin = img_stack.rect->N_bins[1] / N_regions; + const float N_samples = subsampling * N_pix_per_bin; + const int y_max = img_stack.rect->N_bins[0]; + + int x; + + float Delta_y_0 = Delta_EBV[0] / img_stack.rect->dx[0]; + const float y_0 = -img_stack.rect->min[0] / img_stack.rect->dx[0]; + float y, dy; + + // Integer arithmetic is the poor man's fixed-point math + typedef uint32_t fixed_point_t; + const int base_2_prec = 18; // unsigned Q14.18 format + + const fixed_point_t prec_factor_int = (1 << base_2_prec); + const float prec_factor = (float)prec_factor_int; + + fixed_point_t y_int, dy_int; + fixed_point_t y_ceil, y_floor; + fixed_point_t diff; + + // Pre-computed multiplicative factors + float dy_mult_factor = 1. / N_samples / img_stack.rect->dx[0]; + float ret_mult_factor = 1. / (float)subsampling / prec_factor; + + float tmp_ret, tmp_subpixel; + cv::Mat *img; + + // For each image + for(int k=0; k> base_2_prec); + diff = y_int - (y_floor << base_2_prec); + + tmp_ret += (prec_factor_int - diff) * img->at(y_floor, x) + + diff * img->at(y_floor+1, x); + + /* + // 1 + y_int += dy_int; + y_floor = (y_int >> base_2_prec); + diff = y_int - (y_floor << base_2_prec); + + tmp_ret += diff * img->at(y_floor, x) + + (prec_factor_int - diff) * img->at(y_floor+1, x); + + // 2 + y_int += dy_int; + y_floor = (y_int >> base_2_prec); + diff = y_int - (y_floor << base_2_prec); + + tmp_ret += diff * img->at(y_floor, x) + + (prec_factor_int - diff) * img->at(y_floor+1, x); + */ + } + } + + ret[k] = tmp_ret * ret_mult_factor; + } } double lnp_los_extinction(const double *const logEBV, unsigned int N, TLOSMCMCParams& params) { - double lnp = 0.; - - double EBV_tot = 0.; - double EBV_tmp; - double diff_scaled; - - int thread_num = omp_get_thread_num(); - - // Calculate Delta E(B-V) from log(Delta E(B-V)) - float *Delta_EBV = params.get_Delta_EBV(thread_num); - - for(int i=0; i= params.img_stack->rect->max[0]) { return neg_inf_replacement; } - double EBV_tot_idx = ceil((EBV_tot * params.subpixel_max - params.img_stack->rect->min[0]) / params.img_stack->rect->dx[0]); - if(EBV_tot_idx + 1 >= params.img_stack->rect->N_bins[0]) { return neg_inf_replacement; } - - // Prior on total extinction - if((params.EBV_max > 0.) && (EBV_tot > params.EBV_max)) { - lnp -= (EBV_tot - params.EBV_max) * (EBV_tot - params.EBV_max) / (2. * 0.20 * 0.20 * params.EBV_max * params.EBV_max); - } - - // Compute line integrals through probability surfaces - double *line_int = params.get_line_int(thread_num); - los_integral(*(params.img_stack), params.subpixel.data(), line_int, Delta_EBV, N-1); - - // Soften and multiply line integrals - double lnp_indiv; - for(size_t i=0; iN_images; i++) { - //if(line_int[i] < 1.e5*params.p0) { - // line_int[i] += params.p0 * exp(-line_int[i]/params.p0); - //} - if(line_int[i] > params.p0_over_Z[i]) { - lnp_indiv = log(line_int[i]) + log(1. + params.p0_over_Z[i] / line_int[i]); - } else { - lnp_indiv = params.ln_p0_over_Z[i] + log(1. + line_int[i] * params.inv_p0_over_Z[i]); - } - - lnp += lnp_indiv; - - /*#pragma omp critical (cout) - { - std::cerr << i << "(" << params.ln_p0_over_Z[i] <<"): " << log(line_int[i]) << " --> " << lnp_indiv << std::endl; - }*/ - } - - return lnp; + double lnp = 0.; + + double EBV_tot = 0.; + double EBV_tmp; + double diff_scaled; + + int thread_num = omp_get_thread_num(); + + // Calculate Delta E(B-V) from log(Delta E(B-V)) + float *Delta_EBV = params.get_Delta_EBV(thread_num); + + for(int i=0; i= params.img_stack->rect->max[0]) { return neg_inf_replacement; } + double EBV_tot_idx = ceil((EBV_tot * params.subpixel_max - params.img_stack->rect->min[0]) / params.img_stack->rect->dx[0]); + if(EBV_tot_idx + 1 >= params.img_stack->rect->N_bins[0]) { return neg_inf_replacement; } + + // Prior on total extinction + if((params.EBV_max > 0.) && (EBV_tot > params.EBV_max)) { + lnp -= (EBV_tot - params.EBV_max) * (EBV_tot - params.EBV_max) / (2. * 0.20 * 0.20 * params.EBV_max * params.EBV_max); + } + + // Compute line integrals through probability surfaces + double *line_int = params.get_line_int(thread_num); + los_integral(*(params.img_stack), params.subpixel.data(), line_int, Delta_EBV, N-1); + + // Soften and multiply line integrals + double lnp_indiv; + for(size_t i=0; iN_images; i++) { + //if(line_int[i] < 1.e5*params.p0) { + // line_int[i] += params.p0 * exp(-line_int[i]/params.p0); + //} + if(line_int[i] > params.p0_over_Z[i]) { + lnp_indiv = log(line_int[i]) + log(1. + params.p0_over_Z[i] / line_int[i]); + } else { + lnp_indiv = params.ln_p0_over_Z[i] + log(1. + line_int[i] * params.inv_p0_over_Z[i]); + } + + lnp += lnp_indiv; + + /*#pragma omp critical (cout) + { + std::cerr << i << "(" << params.ln_p0_over_Z[i] <<"): " << log(line_int[i]) << " --> " << lnp_indiv << std::endl; + }*/ + } + + return lnp; } void gen_rand_los_extinction(double *const logEBV, unsigned int N, gsl_rng *r, TLOSMCMCParams ¶ms) { - double EBV_ceil = params.img_stack->rect->max[0] / params.subpixel_max; - double mu = 1.5 * params.EBV_guess_max / params.subpixel_max / (double)N; - double EBV_sum = 0.; - - if((params.log_Delta_EBV_prior != NULL) && (gsl_rng_uniform(r) < 0.8)) { - for(size_t i=0; i= 0.95 * EBV_ceil) { - double factor = log(0.95 * EBV_ceil / EBV_sum); - for(size_t i=0; irect->max[0] / params.subpixel_max; + double mu = 1.5 * params.EBV_guess_max / params.subpixel_max / (double)N; + double EBV_sum = 0.; + + if((params.log_Delta_EBV_prior != NULL) && (gsl_rng_uniform(r) < 0.8)) { + for(size_t i=0; i= 0.95 * EBV_ceil) { + double factor = log(0.95 * EBV_ceil / EBV_sum); + for(size_t i=0; i(), col_avg.end()); - int max = 1; - for(int i = col_avg.rows - 1; i > 0; i--) { - if(col_avg.at(i, 0) > 0.001 * max_sum) { - max = i; - break; - } - } - - // Convert bin index to E(B-V) - return max * img_stack.rect->dx[0] + img_stack.rect->min[0]; + cv::Mat stack, col_avg; + + // Stack images + img_stack.stack(stack); + + // Sum across each EBV + cv::reduce(stack, col_avg, 1, cv::REDUCE_AVG); + //float max_sum = *std::max_element(col_avg.begin(), col_avg.end()); + //std::cerr << "max_sum = " << max_sum << std::endl; + + double tot_weight = 0; //std::accumulate(col_avg.begin(), col_avg.end(), 0); + + for(int i = 0; i < col_avg.rows; i++) { + tot_weight += col_avg.at(i, 0); + //std::cerr << "col_avg.at(" << i << ", 0) = " << col_avg.at(i, 0) << std::endl; + } + + //std::cerr << "tot_weight = " << tot_weight << std::endl; + + double partial_sum_weight = 0.; + + for(int i = 0; i < col_avg.rows; i++) { + partial_sum_weight += col_avg.at(i, 0); + if(partial_sum_weight > 0.90 * tot_weight) { + // Return E(B-V) corresponding to bin index + return (double)i * img_stack.rect->dx[0] + img_stack.rect->min[0]; + //std::cerr << "Passed 90% of weight at " << i << std::endl; + } + } + + return (col_avg.rows - 1) * img_stack.rect->dx[0] + img_stack.rect->min[0]; + + //int max = 1; + //for(int i = col_avg.rows - 1; i > 0; i--) { + // std::cerr << " " << i << " : " << col_avg.at(i, 0) << std::endl; + // if(col_avg.at(i, 0) > 0.01 * max_sum) { + // max = i; + // break; + // } + //} + + // Convert bin index to E(B-V) + //return max * img_stack.rect->dx[0] + img_stack.rect->min[0]; } void guess_EBV_profile(TMCMCOptions &options, TLOSMCMCParams ¶ms, int verbosity) { - TNullLogger logger; - - unsigned int N_steps = options.steps / 8; - unsigned int N_samplers = options.samplers; - //if(N_samplers < 10) { N_samplers = 10; } - unsigned int N_runs = options.N_runs; - unsigned int ndim = params.N_regions + 1; - - if(N_steps < 50) { N_steps = 50; } - if(N_steps < 2*ndim) { N_steps = 2*ndim; } - - unsigned int base_N_steps = int(ceil(N_steps/10.)); - - TAffineSampler::pdf_t f_pdf = &lnp_los_extinction; - TAffineSampler::rand_state_t f_rand_state = &gen_rand_los_extinction; - TAffineSampler::reversible_step_t switch_step = &switch_adjacent_log_Delta_EBVs; - TAffineSampler::reversible_step_t mix_step = &mix_log_Delta_EBVs; - TAffineSampler::reversible_step_t move_one_step = &step_one_Delta_EBV; - - TParallelAffineSampler sampler(f_pdf, f_rand_state, ndim, N_samplers*ndim, params, logger, N_runs); - sampler.set_sigma_min(0.001); - sampler.set_scale(1.05); - sampler.set_replacement_bandwidth(0.25); - - sampler.step_MH(2*base_N_steps, true); - //sampler.step(int(N_steps*10./100.), true, 0., 0.); - sampler.step_custom_reversible(base_N_steps, switch_step, true); - - //sampler.step(int(N_steps*10./100), true, 0., 1., true); - sampler.step_MH(base_N_steps, true); - sampler.step_custom_reversible(base_N_steps, switch_step, true); - sampler.step_custom_reversible(base_N_steps, move_one_step, true); - sampler.step(base_N_steps, false, 0., 1., true, true); - - //sampler.step(int(N_steps*10./100.), true, 0., 0.5, true); - //sampler.step(int(N_steps*10./100), true, 0., 1., true); - /*std::cout << "scale: ("; - for(int k=0; k ("; - for(int k=0; k ("; - for(int k=0; k= 2) { - sampler.print_diagnostics(); - std::cout << std::endl; - } - - //std::cout << std::endl; - - //if(verbosity >= 2) { - // sampler.print_stats(); - // std::cout << std::endl << std::endl; - //} - - sampler.get_chain().get_best(params.EBV_prof_guess); + TNullLogger logger; + + unsigned int N_steps = options.steps / 8; + unsigned int N_samplers = options.samplers; + //if(N_samplers < 10) { N_samplers = 10; } + unsigned int N_runs = options.N_runs; + unsigned int ndim = params.N_regions + 1; + + if(N_steps < 50) { N_steps = 50; } + if(N_steps < 2*ndim) { N_steps = 2*ndim; } + + unsigned int base_N_steps = int(ceil(N_steps/10.)); + + TAffineSampler::pdf_t f_pdf = &lnp_los_extinction; + TAffineSampler::rand_state_t f_rand_state = &gen_rand_los_extinction; + TAffineSampler::reversible_step_t switch_step = &switch_adjacent_log_Delta_EBVs; + TAffineSampler::reversible_step_t mix_step = &mix_log_Delta_EBVs; + TAffineSampler::reversible_step_t move_one_step = &step_one_Delta_EBV; + + TParallelAffineSampler sampler(f_pdf, f_rand_state, ndim, N_samplers*ndim, params, logger, N_runs); + sampler.set_sigma_min(0.001); + sampler.set_scale(1.05); + sampler.set_replacement_bandwidth(0.25); + + sampler.step_MH(2*base_N_steps, true); + //sampler.step(int(N_steps*10./100.), true, 0., 0.); + sampler.step_custom_reversible(base_N_steps, switch_step, true); + + //sampler.step(int(N_steps*10./100), true, 0., 1., true); + sampler.step_MH(base_N_steps, true); + sampler.step_custom_reversible(base_N_steps, switch_step, true); + sampler.step_custom_reversible(base_N_steps, move_one_step, true); + sampler.step(base_N_steps, false, 0., 1., true, true); + + //sampler.step(int(N_steps*10./100.), true, 0., 0.5, true); + //sampler.step(int(N_steps*10./100), true, 0., 1., true); + /*std::cout << "scale: ("; + for(int k=0; k ("; + for(int k=0; k ("; + for(int k=0; k= 2) { + sampler.print_diagnostics(); + std::cout << std::endl; + } + + //std::cout << std::endl; + + //if(verbosity >= 2) { + // sampler.print_stats(); + // std::cout << std::endl << std::endl; + //} + + sampler.get_chain().get_best(params.EBV_prof_guess); } struct TEBVGuessParams { - std::vector EBV; - std::vector sigma_EBV; - std::vector sum_weight; - double EBV_max, EBV_ceil; - - TEBVGuessParams(std::vector& _EBV, std::vector& _sigma_EBV, std::vector& _sum_weight, double _EBV_ceil) - : EBV(_EBV.size()), sigma_EBV(_sigma_EBV.size()), sum_weight(_sum_weight.size()) - { - assert(_EBV.size() == _sigma_EBV.size()); - assert(_sum_weight.size() == _sigma_EBV.size()); - std::copy(_EBV.begin(), _EBV.end(), EBV.begin()); - std::copy(_sigma_EBV.begin(), _sigma_EBV.end(), sigma_EBV.begin()); - std::copy(_sum_weight.begin(), _sum_weight.end(), sum_weight.begin()); - EBV_max = -1.; - for(unsigned int i=0; i EBV_max) { EBV_max = EBV[i]; } - } - EBV_ceil = _EBV_ceil; - } + std::vector EBV; + std::vector sigma_EBV; + std::vector sum_weight; + double EBV_max, EBV_ceil; + + TEBVGuessParams(std::vector& _EBV, std::vector& _sigma_EBV, std::vector& _sum_weight, double _EBV_ceil) + : EBV(_EBV.size()), sigma_EBV(_sigma_EBV.size()), sum_weight(_sum_weight.size()) + { + assert(_EBV.size() == _sigma_EBV.size()); + assert(_sum_weight.size() == _sigma_EBV.size()); + std::copy(_EBV.begin(), _EBV.end(), EBV.begin()); + std::copy(_sigma_EBV.begin(), _sigma_EBV.end(), sigma_EBV.begin()); + std::copy(_sum_weight.begin(), _sum_weight.end(), sum_weight.begin()); + EBV_max = -1.; + for(unsigned int i=0; i EBV_max) { EBV_max = EBV[i]; } + } + EBV_ceil = _EBV_ceil; + } }; double lnp_monotonic_guess(const double* Delta_EBV, unsigned int N, TEBVGuessParams& params) { - double lnp = 0; - - double EBV = 0.; - double tmp; - for(unsigned int i=0; i 1.e-10) { - tmp = (EBV - params.EBV[i]) / params.sigma_EBV[i]; - lnp -= 0.5 * tmp * tmp; //params.sum_weight[i] * tmp * tmp; - } - } - - return lnp; + double lnp = 0; + + double EBV = 0.; + double tmp; + for(unsigned int i=0; i 1.e-10) { + tmp = (EBV - params.EBV[i]) / params.sigma_EBV[i]; + lnp -= 0.5 * tmp * tmp; //params.sum_weight[i] * tmp * tmp; + } + } + + return lnp; } void gen_rand_monotonic(double *const Delta_EBV, unsigned int N, gsl_rng *r, TEBVGuessParams ¶ms) { - double EBV_sum = 0.; - double mu = 2. * params.EBV_max / (double)N; - for(size_t i=0; i= 0.95 * params.EBV_ceil) { - double factor = EBV_sum / (0.95 * params.EBV_ceil); - for(size_t i=0; i= 0.95 * params.EBV_ceil) { + double factor = EBV_sum / (0.95 * params.EBV_ceil); + for(size_t i=0; i& Delta_EBV, TMCMCOptions& options) { - std::cout << "stacking images" << std::endl; - // Stack images - cv::Mat stack; - img_stack.stack(stack); - - std::cout << "calculating weighted mean at each distance" << std::endl; - // Weighted mean of each distance - double * dist_y_sum = new double[stack.cols]; - double * dist_y2_sum = new double[stack.cols]; - double * dist_sum = new double[stack.cols]; - for(int k = 0; k < stack.cols; k++) { - dist_y_sum[k] = 0.; - dist_y2_sum[k] = 0.; - dist_sum[k] = 0.; - } - double y = 0.5; - for(int j = 0; j < stack.rows; j++, y += 1.) { - for(int k = 0; k < stack.cols; k++) { - dist_y_sum[k] += y * stack.at(j,k); - dist_y2_sum[k] += y*y * stack.at(j,k); - dist_sum[k] += stack.at(j,k); - } - } - - for(int k = 0; k < stack.cols; k++) { - std::cout << k << "\t" << dist_y_sum[k]/dist_sum[k] << "\t" << sqrt(dist_y2_sum[k]/dist_sum[k]) << "\t" << dist_sum[k] << std::endl; - } - - std::cout << "calculating weighted mean about each anchor" << std::endl; - // Weighted mean in region of each anchor point - std::vector y_sum(N_regions+1, 0.); - std::vector y2_sum(N_regions+1, 0.); - std::vector w_sum(N_regions+1, 0.); - int kStart = 0; - int kEnd; - double width = (double)(stack.cols) / (double)(N_regions); - for(int n = 0; n < N_regions+1; n++) { - std::cout << "n = " << n << std::endl; - if(n == N_regions) { - kEnd = stack.cols; - } else { - kEnd = ceil(((double)n + 0.5) * width); - } - for(int k = kStart; k < kEnd; k++) { - y_sum[n] += dist_y_sum[k]; - y2_sum[n] += dist_y2_sum[k]; - w_sum[n] += dist_sum[k]; - } - kStart = kEnd + 1; - } - - delete[] dist_sum; - delete[] dist_y_sum; - delete[] dist_y2_sum; - - std::cout << "Covert to EBV and sigma_EBV" << std::endl; - // Create non-monotonic guess - Delta_EBV.resize(N_regions+1); - std::vector sigma_EBV(N_regions+1, 0.); - for(int i=0; imin[0] + img_stack.rect->dx[1] * y_sum[n] / w_sum[n]; - sigma_EBV[n] = img_stack.rect->dx[0] * sqrt( (y2_sum[n] - (y_sum[n] * y_sum[n] / w_sum[n])) / w_sum[n] ); - std::cout << n << "\t" << Delta_EBV[n] << "\t+-" << sigma_EBV[n] << std::endl; - } - - // Fit monotonic guess - unsigned int N_steps = 100; - unsigned int N_samplers = 2 * N_regions; - unsigned int N_runs = options.N_runs; - unsigned int ndim = N_regions + 1; - - std::cout << "Setting up params" << std::endl; - TEBVGuessParams params(Delta_EBV, sigma_EBV, w_sum, img_stack.rect->max[0]); - TNullLogger logger; - - TAffineSampler::pdf_t f_pdf = &lnp_monotonic_guess; - TAffineSampler::rand_state_t f_rand_state = &gen_rand_monotonic; - - std::cout << "Setting up sampler" << std::endl; - TParallelAffineSampler sampler(f_pdf, f_rand_state, ndim, N_samplers*ndim, params, logger, N_runs); - sampler.set_scale(1.1); - sampler.set_replacement_bandwidth(0.75); - - std::cout << "Stepping" << std::endl; - sampler.step(int(N_steps*40./100.), true, 0., 0.5); - sampler.step(int(N_steps*10./100), true, 0., 1., true); - sampler.step(int(N_steps*40./100.), true, 0., 0.5); - sampler.step(int(N_steps*10./100), true, 0., 1., true); - - sampler.print_stats(); - - std::cout << "Getting best value" << std::endl; - Delta_EBV.clear(); - sampler.get_chain().get_best(Delta_EBV); - - std::cout << "Monotonic guess" << std::endl; - double EBV_sum = 0.; - for(size_t i=0; i(j,k); + dist_y2_sum[k] += y*y * stack.at(j,k); + dist_sum[k] += stack.at(j,k); + } + } + + for(int k = 0; k < stack.cols; k++) { + std::cout << k << "\t" << dist_y_sum[k]/dist_sum[k] << "\t" << sqrt(dist_y2_sum[k]/dist_sum[k]) << "\t" << dist_sum[k] << std::endl; + } + + std::cout << "calculating weighted mean about each anchor" << std::endl; + // Weighted mean in region of each anchor point + std::vector y_sum(N_regions+1, 0.); + std::vector y2_sum(N_regions+1, 0.); + std::vector w_sum(N_regions+1, 0.); + int kStart = 0; + int kEnd; + double width = (double)(stack.cols) / (double)(N_regions); + for(int n = 0; n < N_regions+1; n++) { + std::cout << "n = " << n << std::endl; + if(n == N_regions) { + kEnd = stack.cols; + } else { + kEnd = ceil(((double)n + 0.5) * width); + } + for(int k = kStart; k < kEnd; k++) { + y_sum[n] += dist_y_sum[k]; + y2_sum[n] += dist_y2_sum[k]; + w_sum[n] += dist_sum[k]; + } + kStart = kEnd + 1; + } + + delete[] dist_sum; + delete[] dist_y_sum; + delete[] dist_y2_sum; + + std::cout << "Covert to EBV and sigma_EBV" << std::endl; + // Create non-monotonic guess + Delta_EBV.resize(N_regions+1); + std::vector sigma_EBV(N_regions+1, 0.); + for(int i=0; imin[0] + img_stack.rect->dx[1] * y_sum[n] / w_sum[n]; + sigma_EBV[n] = img_stack.rect->dx[0] * sqrt( (y2_sum[n] - (y_sum[n] * y_sum[n] / w_sum[n])) / w_sum[n] ); + std::cout << n << "\t" << Delta_EBV[n] << "\t+-" << sigma_EBV[n] << std::endl; + } + + // Fit monotonic guess + unsigned int N_steps = 100; + unsigned int N_samplers = 2 * N_regions; + unsigned int N_runs = options.N_runs; + unsigned int ndim = N_regions + 1; + + std::cout << "Setting up params" << std::endl; + TEBVGuessParams params(Delta_EBV, sigma_EBV, w_sum, img_stack.rect->max[0]); + TNullLogger logger; + + TAffineSampler::pdf_t f_pdf = &lnp_monotonic_guess; + TAffineSampler::rand_state_t f_rand_state = &gen_rand_monotonic; + + std::cout << "Setting up sampler" << std::endl; + TParallelAffineSampler sampler(f_pdf, f_rand_state, ndim, N_samplers*ndim, params, logger, N_runs); + sampler.set_scale(1.1); + sampler.set_replacement_bandwidth(0.75); + + std::cout << "Stepping" << std::endl; + sampler.step(int(N_steps*40./100.), true, 0., 0.5); + sampler.step(int(N_steps*10./100), true, 0., 1., true); + sampler.step(int(N_steps*40./100.), true, 0., 0.5); + sampler.step(int(N_steps*10./100), true, 0., 1., true); + + sampler.print_stats(); + + std::cout << "Getting best value" << std::endl; + Delta_EBV.clear(); + sampler.get_chain().get_best(Delta_EBV); + + std::cout << "Monotonic guess" << std::endl; + double EBV_sum = 0.; + for(size_t i=0; irect->max[0]; - double EBV_sum = 0.; - double guess_sum = 0.; - double factor; - - //if(params.sigma_log_Delta_EBV != NULL) { - // for(size_t i=0; i= 0.95 * EBV_ceil) { - factor = log(0.95 * EBV_ceil / EBV_sum); - for(size_t i=0; irect->max[0]; + double EBV_sum = 0.; + double guess_sum = 0.; + double factor; + + //if(params.sigma_log_Delta_EBV != NULL) { + // for(size_t i=0; i= 0.95 * EBV_ceil) { + factor = log(0.95 * EBV_ceil / EBV_sum); + for(size_t i=0; i= j) { k++; } - - _Y[j] = _X[k]; - _Y[k] = _X[j]; - - // log[Q(Y -> X) / Q(X -> Y)] - return 0.; + for(int i=0; i<_N; i++) { _Y[i] = _X[i]; } + + // Choose two Deltas to switch + int j = gsl_rng_uniform_int(r, _N); + int k = gsl_rng_uniform_int(r, _N-1); + if(k >= j) { k++; } + + _Y[j] = _X[k]; + _Y[k] = _X[j]; + + // log[Q(Y -> X) / Q(X -> Y)] + return 0.; } // Custom reversible step for piecewise-linear model. // Switch two log(Delta E(B-V)) values. double switch_adjacent_log_Delta_EBVs(double *const _X, double *const _Y, unsigned int _N, gsl_rng* r, TLOSMCMCParams& _params) { - for(int i=0; i<_N; i++) { _Y[i] = _X[i]; } - - // Choose which Deltas to switch - int j = gsl_rng_uniform_int(r, _N-1); - - _Y[j] = _X[j+1]; - _Y[j+1] = _X[j]; - - // log[Q(Y -> X) / Q(X -> Y)] - return 0.; + for(int i=0; i<_N; i++) { _Y[i] = _X[i]; } + + // Choose which Deltas to switch + int j = gsl_rng_uniform_int(r, _N-1); + + _Y[j] = _X[j+1]; + _Y[j+1] = _X[j]; + + // log[Q(Y -> X) / Q(X -> Y)] + return 0.; } double mix_log_Delta_EBVs(double *const _X, double *const _Y, unsigned int _N, gsl_rng* r, TLOSMCMCParams& _params) { - for(int i=0; i<_N; i++) { _Y[i] = _X[i]; } - - // Choose two Deltas to mix - int j = gsl_rng_uniform_int(r, _N-1); - int k; - if(gsl_rng_uniform(r) < 0.5) { - k = j; - j += 1; - } else { - k = j+1; - } - //int k = gsl_rng_uniform_int(r, _N-1); - //if(k >= j) { k++; } - double pct = gsl_rng_uniform(r); - - _Y[j] = log(1. - pct) + _X[j]; - _Y[k] = log(exp(_Y[k]) + pct * exp(_X[j])); - - // log[Q(Y -> X) / Q(X -> Y)] - return 2. * _X[j] + _X[k] - 2. * _Y[j] - _Y[k]; + for(int i=0; i<_N; i++) { _Y[i] = _X[i]; } + + // Choose two Deltas to mix + int j = gsl_rng_uniform_int(r, _N-1); + int k; + if(gsl_rng_uniform(r) < 0.5) { + k = j; + j += 1; + } else { + k = j+1; + } + //int k = gsl_rng_uniform_int(r, _N-1); + //if(k >= j) { k++; } + double pct = gsl_rng_uniform(r); + + _Y[j] = log(1. - pct) + _X[j]; + _Y[k] = log(exp(_Y[k]) + pct * exp(_X[j])); + + // log[Q(Y -> X) / Q(X -> Y)] + return 2. * _X[j] + _X[k] - 2. * _Y[j] - _Y[k]; } double step_one_Delta_EBV(double *const _X, double *const _Y, unsigned int _N, gsl_rng* r, TLOSMCMCParams& _params) { - for(int i=0; i<_N; i++) { _Y[i] = _X[i]; } - - // Choose Delta to step in - int j = _N - 1 - gsl_rng_uniform_int(r, _N/2); - - _Y[j] += gsl_ran_gaussian_ziggurat(r, 0.5); - - // log[Q(Y -> X) / Q(X -> Y)] - return 0.; + for(int i=0; i<_N; i++) { _Y[i] = _X[i]; } + + // Choose Delta to step in + int j = _N - 1 - gsl_rng_uniform_int(r, _N/2); + + _Y[j] += gsl_ran_gaussian_ziggurat(r, 0.5); + + // log[Q(Y -> X) / Q(X -> Y)] + return 0.; } /**************************************************************************************************************************** - * + * * TLOSMCMCParams - * + * ****************************************************************************************************************************/ -TLOSMCMCParams::TLOSMCMCParams(TImgStack* _img_stack, const std::vector& _lnZ, double _p0, - unsigned int _N_runs, unsigned int _N_threads, unsigned int _N_regions, - double _EBV_max) - : img_stack(_img_stack), subpixel(_img_stack->N_images, 1.), - N_runs(_N_runs), N_threads(_N_threads), N_regions(_N_regions), - line_int(NULL), Delta_EBV_prior(NULL), - log_Delta_EBV_prior(NULL), sigma_log_Delta_EBV(NULL), - guess_cov(NULL), guess_sqrt_cov(NULL) +TLOSMCMCParams::TLOSMCMCParams( + TImgStack* _img_stack, const std::vector& _lnZ, double _p0, + unsigned int _N_runs, unsigned int _N_threads, unsigned int _N_regions, + double _EBV_max) + : img_stack(_img_stack), subpixel(_img_stack->N_images, 1.), + N_runs(_N_runs), N_threads(_N_threads), N_regions(_N_regions), + line_int(NULL), Delta_EBV_prior(NULL), + log_Delta_EBV_prior(NULL), sigma_log_Delta_EBV(NULL), + guess_cov(NULL), guess_sqrt_cov(NULL) { - line_int = new double[_img_stack->N_images * N_threads]; - Delta_EBV = new float[(N_regions+1) * N_threads]; - - //std::cout << "Allocated line_int[" << _img_stack->N_images * N_threads << "] (" << _img_stack->N_images << " images, " << N_threads << " threads)" << std::endl; - p0 = _p0; - lnp0 = log(p0); - - p0_over_Z.reserve(_lnZ.size()); - inv_p0_over_Z.reserve(_lnZ.size()); - ln_p0_over_Z.reserve(_lnZ.size()); - - for(std::vector::const_iterator it=_lnZ.begin(); it != _lnZ.end(); ++it) { - ln_p0_over_Z.push_back(lnp0 - *it); - p0_over_Z.push_back(exp(lnp0 - *it)); - inv_p0_over_Z.push_back(exp(*it - lnp0)); - } - - EBV_max = _EBV_max; - EBV_guess_max = guess_EBV_max(*img_stack); - subpixel_max = 1.; - subpixel_min = 1.; - alpha_skew = 0.; + line_int = new double[_img_stack->N_images * N_threads]; + Delta_EBV = new float[(N_regions+1) * N_threads]; + + //std::cout << "Allocated line_int[" << _img_stack->N_images * N_threads << "] (" << _img_stack->N_images << " images, " << N_threads << " threads)" << std::endl; + p0 = _p0; + lnp0 = log(p0); + + p0_over_Z.reserve(_lnZ.size()); + inv_p0_over_Z.reserve(_lnZ.size()); + ln_p0_over_Z.reserve(_lnZ.size()); + + for(std::vector::const_iterator it=_lnZ.begin(); it != _lnZ.end(); ++it) { + ln_p0_over_Z.push_back(lnp0 - *it); + p0_over_Z.push_back(exp(lnp0 - *it)); + inv_p0_over_Z.push_back(exp(*it - lnp0)); + } + + EBV_max = _EBV_max; + EBV_guess_max = guess_EBV_max(*img_stack); + subpixel_max = 1.; + subpixel_min = 1.; + alpha_skew = 0.; } TLOSMCMCParams::~TLOSMCMCParams() { - if(line_int != NULL) { delete[] line_int; } - if(Delta_EBV != NULL) { delete[] Delta_EBV; } - if(Delta_EBV_prior != NULL) { delete[] Delta_EBV_prior; } - if(log_Delta_EBV_prior != NULL) { delete[] log_Delta_EBV_prior; } - if(sigma_log_Delta_EBV != NULL) { delete[] sigma_log_Delta_EBV; } - if(guess_cov != NULL) { gsl_matrix_free(guess_cov); } - if(guess_sqrt_cov != NULL) { gsl_matrix_free(guess_sqrt_cov); } + if(line_int != NULL) { delete[] line_int; } + if(Delta_EBV != NULL) { delete[] Delta_EBV; } + if(Delta_EBV_prior != NULL) { delete[] Delta_EBV_prior; } + if(log_Delta_EBV_prior != NULL) { delete[] log_Delta_EBV_prior; } + if(sigma_log_Delta_EBV != NULL) { delete[] sigma_log_Delta_EBV; } + if(guess_cov != NULL) { gsl_matrix_free(guess_cov); } + if(guess_sqrt_cov != NULL) { gsl_matrix_free(guess_sqrt_cov); } } void TLOSMCMCParams::set_p0(double _p0) { - p0 = _p0; - lnp0 = log(p0); + p0 = _p0; + lnp0 = log(p0); } void TLOSMCMCParams::set_subpixel_mask(TStellarData& data) { - assert(data.star.size() == img_stack->N_images); - subpixel.clear(); - subpixel_max = 0.; - subpixel_min = inf_replacement; - double EBV; - for(size_t i=0; i subpixel_max) { subpixel_max = EBV; } - if(EBV < subpixel_min) { subpixel_min = EBV; } - subpixel.push_back(EBV); - } + assert(data.star.size() == img_stack->N_images); + subpixel.clear(); + subpixel_max = 0.; + subpixel_min = inf_replacement; + double EBV; + for(size_t i=0; i subpixel_max) { subpixel_max = EBV; } + if(EBV < subpixel_min) { subpixel_min = EBV; } + subpixel.push_back(EBV); + } } void TLOSMCMCParams::set_subpixel_mask(std::vector& new_mask) { - assert(new_mask.size() == img_stack->N_images); - subpixel.clear(); - subpixel_max = 0.; - subpixel_min = inf_replacement; - for(size_t i=0; i subpixel_max) { subpixel_max = new_mask[i]; } - if(new_mask[i] < subpixel_min) { subpixel_min = new_mask[i]; } - subpixel.push_back(new_mask[i]); - } + assert(new_mask.size() == img_stack->N_images); + subpixel.clear(); + subpixel_max = 0.; + subpixel_min = inf_replacement; + for(size_t i=0; i subpixel_max) { subpixel_max = new_mask[i]; } + if(new_mask[i] < subpixel_min) { subpixel_min = new_mask[i]; } + subpixel.push_back(new_mask[i]); + } } // Calculate the mean and std. dev. of log(delta_EBV) -void TLOSMCMCParams::calc_Delta_EBV_prior(TGalacticLOSModel& gal_los_model, double EBV_tot, int verbosity) { - double mu_0 = img_stack->rect->min[1]; - double mu_1 = img_stack->rect->max[1]; - assert(mu_1 > mu_0); - - int subsampling = 100; - double Delta_mu = (mu_1 - mu_0) / (double)(N_regions * subsampling); - - // Allocate space for information on priors - if(Delta_EBV_prior != NULL) { delete[] Delta_EBV_prior; } - Delta_EBV_prior = new double[N_regions+1]; - - if(log_Delta_EBV_prior != NULL) { delete[] log_Delta_EBV_prior; } - log_Delta_EBV_prior = new double[N_regions+1]; - - if(sigma_log_Delta_EBV != NULL) { delete[] sigma_log_Delta_EBV; } - sigma_log_Delta_EBV = new double[N_regions+1]; - - /*for(double x = 0.; x < 20.5; x += 1.) { - std::cout << "rho(DM = " << x << ") = " << std::setprecision(5) << gal_los_model.dA_dmu(x) / pow10(x/5.) << std::endl; - }*/ - - // Normalization information - double sigma = 1.4; - double log_Delta_EBV_floor = -8.; - double dEBV_ds = 0.2; // mag kpc^{-1} - - // Determine normalization - double ds_dmu = 10. * log(10.) / 5. * pow10(-10./5.); - double dEBV_ds_local = gal_los_model.dA_dmu(-10.) / ds_dmu * exp(0.5 * sigma * sigma); - double norm = 0.001 * dEBV_ds / dEBV_ds_local; - double log_norm = log(norm); - - // Integrate Delta E(B-V) from close distance to mu_0 - double mu = mu_0 - 5 * Delta_mu * (double)subsampling; - Delta_EBV_prior[0] = 0.; - for(int k=0; k<5*subsampling; k++, mu += Delta_mu) { - Delta_EBV_prior[0] += gal_los_model.dA_dmu(mu); - } - Delta_EBV_prior[0] *= Delta_mu; - - // Integrate Delta E(B-V) in each region - for(int i=1; i= 2) { - std::cout << "Delta_EBV_prior:" << std::endl; - } - - double EBV_sum = 0.; - mu = mu_0; - - for(int i=0; i= 2) { - std::cout << std::setprecision(5) - << pow10(mu / 5. - 2.) - << "\t" << mu - << "\t" << log_Delta_EBV_prior[i] - << " +- " << sigma_log_Delta_EBV[i] - << " -> " << Delta_EBV_prior[i] * exp(0.5 * sigma_log_Delta_EBV[i] * sigma_log_Delta_EBV[i]) - << std::endl; - } - - mu += (mu_1 - mu_0) / (double)N_regions; - } - - if(verbosity >= 2) { - std::cout << "Total E(B-V) = " << EBV_sum << std::endl; - std::cout << std::endl; - } - - // Convert means and errors for skew normal distribution - alpha_skew = 1.; - double delta_skew = alpha_skew / (1. + alpha_skew*alpha_skew); - - if(verbosity >= 2) { - std::cout << "Skewed mean/variance:" << std::endl; - } - - for(int i=0; i= 2) { - std::cout << std::setprecision(6) - << "\t" << log_Delta_EBV_prior[i] - << " +- " << sigma_log_Delta_EBV[i] << std::endl; - } - } - - if(verbosity >= 2) { - std::cout << std::endl; - } - - delete[] log_Delta_EBV_bias; -} +void TLOSMCMCParams::calc_Delta_EBV_prior(TGalacticLOSModel& gal_los_model, + double log_Delta_EBV_floor, + double log_Delta_EBV_ceil, + double EBV_tot, + double sigma, + int verbosity) { + double mu_0 = img_stack->rect->min[1]; + double mu_1 = img_stack->rect->max[1]; + assert(mu_1 > mu_0); + int subsampling = 100; + double Delta_mu = (mu_1 - mu_0) / (double)(N_regions * subsampling); -void TLOSMCMCParams::gen_guess_covariance(double scale_length) { - if(guess_cov != NULL) { gsl_matrix_free(guess_cov); } - if(guess_sqrt_cov != NULL) { gsl_matrix_free(guess_sqrt_cov); } - - guess_cov = gsl_matrix_alloc(N_regions+1, N_regions+1); - guess_sqrt_cov = gsl_matrix_alloc(N_regions+1, N_regions+1); - - // Generate guess covariance matrix - double val; - - for(int k=0; k log_Delta_EBV_ceil) { + log_Delta_EBV_prior[i] = log_Delta_EBV_ceil; + } + + Delta_EBV_prior[i] = exp(log_Delta_EBV_prior[i]); + + EBV_sum += Delta_EBV_prior[i] * exp(0.5 * sigma_log_Delta_EBV[i] * sigma_log_Delta_EBV[i]); + + if(verbosity >= 2) { + std::cout << std::setprecision(5) + << exp10(mu / 5. - 2.) + << "\t" << mu + << "\t" << log_Delta_EBV_prior[i] + << " +- " << sigma_log_Delta_EBV[i] + << " -> " << Delta_EBV_prior[i] * exp(0.5 * sigma_log_Delta_EBV[i] * sigma_log_Delta_EBV[i]) + << std::endl; + } + + mu += (mu_1 - mu_0) / (double)N_regions; + } + + if(verbosity >= 2) { + std::cout << "Total E(B-V) = " << EBV_sum << std::endl; + std::cout << std::endl; + } + + // Convert means and errors for skew normal distribution + // alpha_skew = 1.; + double delta_skew = alpha_skew / (1. + alpha_skew*alpha_skew); + + if(verbosity >= 2) { + std::cout << "Skewed mean/variance:" << std::endl; + } + + for(int i=0; i= 2) { + std::cout << std::setprecision(6) + << "\t" << log_Delta_EBV_prior[i] + << " +- " << sigma_log_Delta_EBV[i] << std::endl; + } + } + + if(verbosity >= 2) { + std::cout << std::endl; + } + + delete[] log_Delta_EBV_bias; +} + + +void TLOSMCMCParams::gen_guess_covariance(double scale_length) { + if(guess_cov != NULL) { gsl_matrix_free(guess_cov); } + if(guess_sqrt_cov != NULL) { gsl_matrix_free(guess_sqrt_cov); } + + guess_cov = gsl_matrix_alloc(N_regions+1, N_regions+1); + guess_sqrt_cov = gsl_matrix_alloc(N_regions+1, N_regions+1); + + // Generate guess covariance matrix + double val; + + for(int k=0; kN_images * thread_num; +} + +float* TLOSMCMCParams::get_Delta_EBV(unsigned int thread_num) { + assert(thread_num < N_threads); + return Delta_EBV + (N_regions+1) * thread_num; +} + + +/**************************************************************************************************************************** + * + * TDiscreteLosMcmcParams + * + ****************************************************************************************************************************/ + +TDiscreteLosMcmcParams::TDiscreteLosMcmcParams( + std::unique_ptr _img_stack, + std::unique_ptr _neighbor_pixels, + unsigned int _N_runs, + unsigned int _N_threads, + int verbosity) + : img_stack(std::move(_img_stack)), + neighbor_pixels(std::move(_neighbor_pixels)), + N_runs(_N_runs), N_threads(_N_threads) +{ + // Initialize random number generator + std::random_device rd; + std::vector seeds = { + rd(), + static_cast(std::chrono::high_resolution_clock::now().time_since_epoch().count()) + }; + std::seed_seq seq(seeds.begin(), seeds.end()); + std::mt19937 r(seq); + + // Number of distance, reddening bins + n_dists = img_stack->rect->N_bins[1]; + n_E = img_stack->rect->N_bins[0]; + + // Line integrals through p(dm, E) of each star + line_int = new double[img_stack->N_images * N_threads]; + + E_pix_idx = new int16_t[n_dists * N_threads]; + + y_zero_idx = -img_stack->rect->min[0] / img_stack->rect->dx[0]; + + // Priors + mu_log_dE = -10.; + set_sigma_log_dE(0.75); + //sigma_log_dE = 0.75; // TODO: Make this configurable + mu_log_dy = mu_log_dE - log(img_stack->rect->dx[0]); + //inv_sigma_log_dy = 1. / sigma_log_dE; + inv_sigma_dy_neg = 1. / 0.1; + + priors_subsampling = 1; //10; + + log_P_dy = std::make_shared(); + + if(verbosity >= 2) { + std::cerr << "n_dists = " << n_dists << std::endl; + std::cerr << "n_E = " << n_E << std::endl; + std::cerr << "y_zero_idx = " << y_zero_idx << std::endl; + std::cerr << "mu_log_dy = " << mu_log_dy << std::endl; + std::cerr << "inv_sigma_log_dy = " << inv_sigma_log_dy + << std::endl; + } +} + + +TDiscreteLosMcmcParams::~TDiscreteLosMcmcParams() { + if(line_int != NULL) { delete[] line_int; } + if(E_pix_idx != NULL) { delete[] E_pix_idx; } +} + + +void TDiscreteLosMcmcParams::set_sigma_log_dE(const double s) { + sigma_log_dE = s; + inv_sigma_log_dy = 1. / s; +} + + +void randomize_neighbors( + TNeighborPixels& neighbor_pixels, + std::vector& neighbor_sample, + std::mt19937& r) +{ + // Choose random neighbor samples + std::uniform_int_distribution u(0, neighbor_pixels.get_n_samples()); + neighbor_sample.clear(); + for(int i=0; iset_delta((double)(y_idx[i]), 0, 0, i); + } + //std::cerr << std::endl; + neighbor_pixels->apply_priors_indiv( + mu_log_dE_0, + sigma_log_dE_0, + img_stack->rect->dx[0], + 0, 0); +} + + +double neighbor_gibbs_step( + int pix, + TNeighborPixels& neighbor_pixels, + std::vector& neighbor_sample, + std::vector& log_p_sample_ws, + std::vector& p_sample_ws, + std::mt19937& r, + double beta) +{ + // Takes a Gibbs step in one of the neighboring pixels, choosing + // a sample at random, weighted by the Gaussian process prior. + + double mu, ivar, dx; + + int n_samples = neighbor_pixels.get_n_samples(); + int n_dists = neighbor_pixels.get_n_dists(); + + log_p_sample_ws.resize(n_samples); + + // Determine chi^2 of each sample + for(int sample=0; sampleget_delta(k, s, dist); + // } + // std::cerr << std::endl + // << " x = " << mu << " +- " << 1./std::sqrt(ivar) + // << std::endl + // << " delta[1] = " << neighbor_pixels->get_delta(1, sample, dist) + // << std::endl + // << " dx = " << dx + // << std::endl + // << " chi^2 = " << ivar * dx*dx + // << std::endl; + //} + } + + log_p_sample_ws[sample] *= -0.5; + + // Prior term + log_p_sample_ws[sample] -= neighbor_pixels.get_prior(pix, sample); + } + + // Turn chi^2 into probability + //std::cerr << "p_sample.size() = " << p_sample.size() << std::endl; + double log_p_max = *std::max_element(log_p_sample_ws.begin(), log_p_sample_ws.end()); + //std::cerr << std::endl + // << "p_min = " << p_min << std::endl; + for(int sample=0; sample d(p_sample_ws.begin(), p_sample_ws.end()); + int idx = d(r); + neighbor_sample[pix] = idx; + + //if(pix == 1) { + // std::vector p = d.probabilities(); + // std::sort(p.begin(), p.end()); + + // std::cerr << "Probabilities:"; + // for(int i=p.size()-1; (i>0) && (i>p.size()-10); i--) { + // std::cerr << " " << p.at(i); + // } + // std::cerr << std::endl; + + // double P_tot = 0; + // int n_eff = 0; + // for(auto pp = p.rbegin(); (pp != p.rend()) && (P_tot < 0.99); ++pp, ++n_eff) { + // P_tot += *pp; + // } + // std::cerr << "n_eff(" << pix << ") = " << n_eff << std::endl; + //} + //std::cerr << std::endl; + + return log_p_sample_ws[idx]; +} + + +std::unique_ptr> +neighbor_gibbs_step_shifted_factory( + const int pix, + TNeighborPixels& neighbor_pixels, + const std::vector& neighbor_sample, + std::vector& log_p_sample_ws, + std::vector& p_sample_ws, + const double beta, + const double shift_weight) +{ + // Returns a pointer containing a discrete_distribution, + // which allows one to take Gibbs steps in one of the + // neighboring pixels. The new samples are + // chosen at random, weighted by the Gaussian process prior. + + double mu, ivar, dx; + + int n_samples = neighbor_pixels.get_n_samples(); + int n_dists = neighbor_pixels.get_n_dists(); + + log_p_sample_ws.resize(n_samples); + + // Determine chi^2 of each sample + for(int sample=0; sample>( + p_sample_ws.begin(), + p_sample_ws.end() + ); +} + + +struct NeighborGibbsCacheData { + // Data required in cache to speed up Gibbs steps in + // neighboring pixels. + std::vector samples; + std::vector mu; +}; + + +std::unique_ptr +neighbor_gibbs_step_shifted_cache_data( + const int pix, + TNeighborPixels& neighbor_pixels, + const std::vector& neighbor_sample, + std::vector& log_p_sample_ws, + std::vector& p_sample_ws, + std::vector& mu_ws, + const double beta, + const double shift_weight, + const double lnp_cutoff) +{ + // Gather cache data allowing one to execute a Gibbs step + // in one of the neighboring pixels, choosing + // a sample at random, weighted by the Gaussian process prior. + + double mu, ivar, dx; + + const int n_samples = neighbor_pixels.get_n_samples(); + const int n_dists = neighbor_pixels.get_n_dists(); + + log_p_sample_ws.resize(n_samples); + mu_ws.resize(n_samples*n_dists); + + // Determine chi^2 of each sample + uint32_t k = 0; + for(int sample=0; sample cache_data + = std::make_unique(); + + cache_data->samples.reserve(n_samples); + for(int sample=0; sample lnp_cutoff) { + cache_data->samples.push_back(sample); + } + } + + const int n_samples_cached = cache_data->samples.size(); + cache_data->mu.reserve(n_dists*n_samples_cached); + for(auto s : cache_data->samples) { + for(int k=s*n_dists; k<(s+1)*n_dists; k++) { + cache_data->mu.push_back(mu_ws[k]); + } + } + + return std::move(cache_data); +} + + +//typedef LRUCache::CachedFunction< +// std::vector, +// std::shared_ptr, +// LRUCache::VectorHasher +// > NeighborGibbsCache; + + +int neighbor_gibbs_step_shifted_cached( + const int pix, + NeighborGibbsCacheData& cache_data, + TNeighborPixels& neighbor_pixels, + const std::vector& neighbor_sample, + std::vector& log_p_sample_ws, + std::vector& p_sample_ws, + std::vector& mu_ws, + const double beta, + const double shift_weight, + const double lnp_cutoff, + std::mt19937& r) +{ + // Calculate ln(p) for each sample + const int n_dists = neighbor_pixels.get_n_dists(); + const int n_samples = cache_data.samples.size(); + + double mu, dx, ivar; + double inv_cov_0; + double inv_cov_m1; + double inv_cov_p1; + + int j = 0; + + for(int i=0; i dd( + p_sample_ws.begin(), + p_sample_ws.begin()+n_samples + ); + + return dd(r); +} + + +double neighbor_gibbs_step_shifted( + const int pix, + TNeighborPixels& neighbor_pixels, + std::vector& neighbor_sample, + std::vector& log_p_sample_ws, + std::vector& p_sample_ws, + std::mt19937& r, + const double beta, + const double shift_weight) +{ + // Takes a Gibbs step in one of the neighboring pixels, choosing + // a sample at random, weighted by the Gaussian process prior. + + double mu, ivar, dy, y; + + int n_samples = neighbor_pixels.get_n_samples(); + int n_dists = neighbor_pixels.get_n_dists(); + + log_p_sample_ws.resize(n_samples); + + const int track_pix = 1; + + for(int sample=0; sample 0.9999)) { + // double p0 = log_p_sample_ws[sample]; + // double p1 = neighbor_pixels.get_prior(pix, sample); + // std::cerr << "log(prior_" << sample << "): " + // << p0 + // << " " + // << p1 + // << " : " + // << p0-p1 + // << std::endl; + //} + + // Prior and likelihood terms + log_p_sample_ws[sample] -= + neighbor_pixels.get_prior(pix, sample) + + (1.-beta) * neighbor_pixels.get_likelihood(pix, sample); + + //if((pix == track_pix) && ((sample == 82) || (sample == 83))) { + // std::cerr << std::endl << std::endl; + //} + } + + // Turn chi^2 into probability + //std::cerr << "p_sample.size() = " << p_sample.size() << std::endl; + double log_p_max = *std::max_element( + log_p_sample_ws.begin(), + log_p_sample_ws.end() + ); + //std::cerr << std::endl + // << "p_min = " << p_min << std::endl; + for(int sample=0; sample d(p_sample_ws.begin(), p_sample_ws.end()); + int idx = d(r); + neighbor_sample[pix] = idx; + + // Calculate entropy of distribution + //if((pix == track_pix) && (beta >= 0.9999)) { + //if(beta >= 0.9999) { + // double plnp = 0.; + // for(auto p : d.probabilities()) { + // if(p > 1.e-10) { + // plnp += p * std::log(p); + // } + // } + // double n_eff = std::exp(-1. * plnp); + // std::cerr << "n_eff_" << pix << "(b=" << beta << ")" << " = " << n_eff << std::endl; + //} + + //if(pix == 2) { + // std::cerr << "beta = " << beta << std::endl; + // std::vector p = d.probabilities(); + + // int p_max_idx = std::distance( + // p.begin(), + // std::max_element(p.begin(), p.end()) + // ); + + // std::sort(p.begin(), p.end()); + + // std::cerr << "Probabilities:"; + // for(int i=p.size()-1; (i>0) && (i>p.size()-10); i--) { + // std::cerr << " " << p.at(i); + // } + // std::cerr << std::endl; + + // std::cerr << "Index of max. prob.: " << p_max_idx << std::endl; + + // double P_tot = 0; + // int n_eff = 0; + // for(auto pp = p.rbegin(); (pp != p.rend()) && (P_tot < 0.99); ++pp, ++n_eff) { + // P_tot += *pp; + // } + // std::cerr << "n_eff(" << pix << ") = " << n_eff << std::endl; + //} + //std::cerr << std::endl; + + return log_p_sample_ws[idx] - log_p_sample_ws[idx_old]; +} + + + +double neighbor_gibbs_step_shifted_2( + int pix, + TNeighborPixels& neighbor_pixels, + std::vector& neighbor_sample, + double log_w_shift, + std::vector& log_p_sample_ws, + std::vector& p_sample_ws, + std::mt19937& r, + double beta) +{ + // Takes a Gibbs step in one of the neighboring pixels, choosing + // a sample at random, weighted by the Gaussian process prior. + + double mu, ivar, dx; + + int n_samples = neighbor_pixels.get_n_samples(); + int n_dists = neighbor_pixels.get_n_dists(); + + log_p_sample_ws.resize(n_samples*3); + + // Determine chi^2 of each sample + for(int sample=0; sample0) && (i>p.size()-10); i--) { + // std::cerr << " " << p.at(i); + // } + // std::cerr << std::endl; + + // double P_tot = 0; + // int n_eff = 0; + // for(auto pp = p.rbegin(); (pp != p.rend()) && (P_tot < 0.99); ++pp, ++n_eff) { + // P_tot += *pp; + // } + // std::cerr << "n_eff(" << pix << ") = " << n_eff << std::endl; + //} + //std::cerr << std::endl; + + return (log_p_sample_ws[idx] - log_p_sample_ws[idx_old]) / beta; +} + + +void TDiscreteLosMcmcParams::initialize_priors( + TGalacticLOSModel& gal_los_model, + double log_Delta_EBV_floor, + double log_Delta_EBV_ceil, + double sigma_log_Delta_EBV, + int verbosity) +{ + // Calculate log-normal prior on reddening increase at each distance + std::cerr << "Initializing discrete l.o.s. priors ..." << std::endl; + std::vector lnZ_dummy; + TLOSMCMCParams los_params( + img_stack.get(), + lnZ_dummy, + 0., 11, 1, + n_dists + ); + los_params.alpha_skew = 0.; + set_sigma_log_dE(sigma_log_Delta_EBV); + los_params.calc_Delta_EBV_prior( + gal_los_model, + log_Delta_EBV_floor, + log_Delta_EBV_ceil, + 0., + sigma_log_dE, + verbosity + ); + + mu_log_dE_0.reserve(n_dists); + sigma_log_dE_0.reserve(n_dists); + for(int i=0; iget_n_samples()); + log_p_sample.resize(neighbor_pixels->get_n_samples()); + + // Scale reddening values in neighbor pixels + neighbor_pixels->apply_priors( + mu_log_dE_0, + sigma_log_dE_0, + img_stack->rect->dx[0]); + } + + if(!neighbor_pixels) { + std::vector neighbors_sample_tmp; + update_priors_image( + neighbors_sample_tmp, + 0., + priors_subsampling, + -1., + verbosity + ); + } + + std::cerr << "Done initializing discrete l.o.s. priors ..." << std::endl; +} + + +void TDiscreteLosMcmcParams::update_priors_image( + std::vector& neighbor_sample, + double alpha_skew, + int subsampling, + const double shift_weight, + int verbosity) +{ + update_priors_image( + *log_P_dy, + neighbor_sample, + alpha_skew, + subsampling, + shift_weight, + verbosity + ); +} + + +void TDiscreteLosMcmcParams::update_priors_image( + cv::Mat& img, + std::vector& neighbor_sample, + double alpha_skew, + int subsampling, + const double shift_weight, + int verbosity) +{ + // Evaluate the probability mass for each (reddening jump, distance) + img = cv::Mat::zeros(n_E, n_dists, CV_FLOATING_TYPE); + + double dE0, dE, P_dist; + + // Cache value of log(dE) for each dE + std::vector log_dE_cache; + log_dE_cache.reserve(n_E * subsampling); + for(int y=0; yrect->dx[0]; + for(int k=0; krect->dx[0]; + log_dE_cache.push_back(std::log(dE)); + } + } + + for(int x=0; x and sigma_{log(dE)} at this distance + double mu, inv_var; + if(neighbor_pixels) { + inv_var = neighbor_pixels->get_inv_var(0, x); + + if(shift_weight > 0.) { + mu = neighbor_pixels->calc_mean_shifted( + 0, x, neighbor_sample, shift_weight); + } else { + mu = neighbor_pixels->calc_mean(0, x, neighbor_sample); + } + //if(shift_weight < std::exp(-1.9)) { + // std::cerr << "x = " << x << std::endl + // << " * mu = " << mu << std::endl + // << " * sigma = " << 1./std::sqrt(inv_var) << std::endl; + //} + } else { + mu = 0.; + inv_var = 1.; + } + double sigma_0 = sigma_log_dE_0.at(x); + mu *= sigma_0; + mu += mu_log_dE_0.at(x); + inv_var /= sigma_0*sigma_0; + + // Calculate the probability of each reddening jump at this distance + P_dist = 0.; + + double log_scale_tmp = std::log(img_stack->rect->dx[0]); + + // Handle dy = 0 as a special case + if(mu < log_scale_tmp) { + // 1.5 is a fudge factor + img.at(0, x) = subsampling / img_stack->rect->dx[0] * 1.5; + P_dist += img.at(0, x); + } else { + double delta = log_scale_tmp - mu; + img.at(0, x) = subsampling * std::exp(-0.5*delta*delta*inv_var) + / img_stack->rect->dx[0] * 1.5; + P_dist += img.at(0, x); + } + + // Handle dy > 0 + for(int y=1; yrect->dx[0]; + for(int k=0; krect->dx[0]; + double log_dE = log_dE_cache[y*subsampling+k]; + if(std::isfinite(log_dE)) {//dE > 0) { + double delta = log_dE - mu; + double P_tmp = std::exp(-0.5 * delta*delta * inv_var); + // TODO: Remove alpha_skew parameter & option + //P_tmp *= 1. + erf(alpha_skew * score * INV_SQRT2); + P_tmp /= dE; + img.at(y, x) += P_tmp; + } + } + // P_dy->at(y, x) /= subsampling; + P_dist += img.at(y, x); + } + + //if(mu < log_scale_tmp) { + // std::cerr << "mu_{" << x << "} = " << mu << " < " << log_scale_tmp << std::endl; + // for(int y=0; y<10; y++) { + // std::cerr << "P_{" << x << ", " << y << "} = " << img.at(y, x) << std::endl; + // } + //} + + // Normalize total probability at this distance to unity + for(int y=0; y 0) { + img.at(y, x) /= P_dist; + } + img.at(y, x) = std::log(img.at(y, x)); + if(img.at(y, x) < -100.) { + img.at(y, x) = -100. - 0.01 * y*y; + } + } + + if(img.at(0, x) <= -99.999) { + img.at(0, x) = 0.; + } + + //if(mu < log_scale_tmp) { + // for(int y=0; y<10; y++) { + // std::cerr << "ln P'_{" << x << ", " << y << "} = " << img.at(y, x) << std::endl; + // } + //} + } + + //if(verbosity >= 2) { + // std::cerr << std::endl + // << "log P(dy):" << std::endl + // << "==========" << std::endl; + // for(int x=0; x(y, x) << " "; + // } + // std::cerr << "... "; + // for(int y=15; y<=30; y+=5) { + // std::cerr << img.at(y, x) << " "; + // } + // std::cerr << std::endl; + // } + // std::cerr << std::endl; + //} + + //std::cerr << "Done initializing discrete l.o.s. priors." << std::endl; +} + + +double* TDiscreteLosMcmcParams::get_line_int(unsigned int thread_num) { + assert(thread_num < N_threads); + return line_int + img_stack->N_images * thread_num; +} + + +int16_t* TDiscreteLosMcmcParams::get_E_pix_idx(unsigned int thread_num) { + assert(thread_num < N_threads); + return E_pix_idx + n_dists * thread_num; +} + + +// Calculates the line integrals for a model in which each distance bin has a +// (possibly) different, constant reddening. +// +// Reddening is discretized, so that it is described by an integer, called the +// y-value or -index. The distance is called the x-value or -index. +// +// Inputs: +// y_idx : Pointer to array containing the y-value in each distance bin. +// line_int_ret : Pointer to array that will store the line integrals. +// +void TDiscreteLosMcmcParams::los_integral_discrete( + const int16_t *const y_idx, + double *const line_int_ret) +{ + // For each image + for(int k = 0; k < img_stack->N_images; k++) { + line_int_ret[k] = 0.; + + // For each distance + for(int j = 0; j < n_dists; j++) { + line_int_ret[k] += (double)img_stack->img[k]->at(y_idx[j], j); + } + + // line_int_ret[k] *= img_stack->rect->dx[1]; // Multiply by dDM + } + // line_int_ret[0] = 1.; // TODO: remove this line. +} + + +// Calculates the change to the line integrals for a step that changes the +// value of E in one distance bin. +// +// Inputs: +// x_idx : Index of distance bin to change. +// y_idx_old : Old y-value of the given distance bin. +// y_idx_new : New y-value of the given distance bin. +// delta_line_int_ret : Pointer to array that will store updated line integrals. +// +void TDiscreteLosMcmcParams::los_integral_diff_step( + const int16_t x_idx, + const int16_t y_idx_old, + const int16_t y_idx_new, + double *const delta_line_int_ret) +{ + // For each image + for(int k=0; k < img_stack->N_images; k++) { + delta_line_int_ret[k] = (double)img_stack->img[k]->at(y_idx_new, x_idx) + - (double)img_stack->img[k]->at(y_idx_old, x_idx); + // delta_line_int_ret[k] *= img_stack->rect->dx[1]; // Multiply by dDM + } +} + + +floating_t TDiscreteLosMcmcParams::log_dy_prior( + const int16_t x_idx, + const int16_t dy, + const cv::Mat& lnP_dy) +{ + // if(dy > 0) { + // float dxi = inv_sigma_log_dy * (log((float)dy) - mu_log_dy); + // return -0.5 * dxi*dxi; + // } else if(dy == 0) { + // float dxi = inv_sigma_log_dy * mu_log_dy; + // return -0.5 * dxi*dxi; + // } else { + // float dxi = inv_sigma_dy_neg * (float)dy; + // return -0.5 * dxi*dxi; + // } + if((dy < 0) || (dy >= lnP_dy.cols)) { + return -std::numeric_limits::infinity(); + } else { + return lnP_dy.at(dy, x_idx); + } +} + + +floating_t TDiscreteLosMcmcParams::log_dy_prior( + const int16_t x_idx, + const int16_t dy) +{ + return log_dy_prior(x_idx, dy, *log_P_dy); +} + + +floating_t TDiscreteLosMcmcParams::log_prior( + const int16_t *const y_idx, + const cv::Mat& lnP_dy) +{ + floating_t dy = y_idx[0] - (int)y_zero_idx; + floating_t log_p = log_dy_prior(0, dy, lnP_dy); + + for(int x=1; xN_images; k++) { + delta_line_int_ret[k] = (double)img_stack->img[k]->at(y_new, x0_idx) + - (double)img_stack->img[k]->at(y_old, x0_idx); + // delta_line_int_ret[k] *= img_stack->rect->dx[1]; // Multiply by dDM + } +} + + +bool TDiscreteLosMcmcParams::shift_r_step_valid( + const int16_t x_idx, + const int16_t dy, + const int16_t *const y_idx_old) { + // Determine whether shift causes y to go above maximum or below zero + for(int j=x_idx; j= n_E)) { + return false; + } + } + return true; +} + + +bool TDiscreteLosMcmcParams::shift_l_step_valid( + const int16_t x_idx, + const int16_t dy, + const int16_t *const y_idx_old) { + // Determine whether shift causes y to go above maximum or below zero + for(int j=0; j<=x_idx; j++) { + if((y_idx_old[j]+dy < 0) || (y_idx_old[j]+dy >= n_E)) { + return false; + } + } + return true; +} + + +void TDiscreteLosMcmcParams::los_integral_diff_shift_r( + const int16_t x_idx, + const int16_t dy, + const int16_t *const y_idx_old, + double *const delta_line_int_ret) { + // Determine whether shift causes y to go above maximum or below zero + // for(int j=x_idx; j= n_E)) { + // // Set line integrals to -infinity + // for(int k=0; k < img_stack->N_images; k++) { + // delta_line_int_ret[k] = -std::numeric_limits::infinity(); + // } + // // Bail out before calculating line integrals, which will try + // // to access out-of-bounds memory. + // return; + // } + // } + + // Determine difference in line integral + + // For each image + for(int k=0; k < img_stack->N_images; k++) { + delta_line_int_ret[k] = 0; + + // For each distance + for(int j=x_idx; jimg[k]->at(y_idx_old[j]+dy, j) + - (double)img_stack->img[k]->at(y_idx_old[j], j); + } + } +} + +void TDiscreteLosMcmcParams::los_integral_diff_shift_l( + const int16_t x_idx, + const int16_t dy, + const int16_t *const y_idx_old, + double *const delta_line_int_ret) { + // Determine difference in line integral + // For each image + for(int k=0; k < img_stack->N_images; k++) { + delta_line_int_ret[k] = 0; + + // For each distance + for(int j=0; j<=x_idx; j++) { + delta_line_int_ret[k] += + (double)img_stack->img[k]->at(y_idx_old[j]+dy, j) + - (double)img_stack->img[k]->at(y_idx_old[j], j); + } + } +} + +void TDiscreteLosMcmcParams::los_integral_diff_shift_compare_operations( + const int16_t x_idx, + const int16_t dy, + const int16_t *const y_idx_old, + unsigned int& n_eval_diff, + unsigned int& n_eval_cumulative) { + // Determine number of jumps in old and new line-of-sight reddening profile + n_eval_diff = 2 * (n_dists - x_idx); + n_eval_cumulative = 4; + + for(int j=x_idx+1; jrect->N_bins[1]; + int n_y = n_E; //img_stack->rect->N_bins[0]; + double dy = img_stack->rect->dx[0]; + + double *y = new double[n_x]; + y[0] = gsl_ran_chisq(r, 1); + + for(int i = 1; i < n_x; i++) { + y[i] = y[i-1] + gsl_ran_chisq(r, 1); + } + + double y_scale = (EBV_max_guess / y[n_x - 1]) / dy; + + for(int i = 0; i < n_x; i++) { + y_idx_ret[i] = (int16_t)ceil(y[i] * y_scale + y_zero_idx); + + if(y_idx_ret[i] >= n_y) { + y_idx_ret[i] = (int16_t)(n_y - 1); + } + } + + delete[] y; +} + + +void ascii_progressbar( + int state, + int max_state, + int width, + double t_elapsed, + std::ostream& out, + bool terminate=true, + bool rollback=false) +{ + double pct = (double)state / (double)(max_state-1); + int n_ticks = pct * width; + + if(rollback) { + out << ' ' << '\r'; + } + + out << "|"; + for(int i=0; i"; + } + for(int i=n_ticks; i " << idx << std::endl; + } + + // Add in y labels + for(int k = 0; k < img_y; k++) { + idx = row_width * k + n_x + 1; + ascii_img[idx] = '|'; + } + + for(int k=img_y-1; k>=0; k-=5) { + idx = row_width * k + n_x + 2; + ascii_img[idx] = '-'; + + const char* fmt = "%4.2f"; + double y_label = (img_y - 1 - k) * dy / y_scale; + int label_len = std::snprintf(nullptr, 0, fmt, y_label); + std::vector buf(label_len + 1); + std::snprintf(&buf[0], buf.size(), fmt, y_label); + + idx += 2; + for(int j=0; j<4; j++) { + ascii_img[idx + j] = buf[j]; + } + } + + // Add in x labels + for(int k=0; k buf(label_len + 1); + std::snprintf(&buf[0], buf.size(), fmt, x_label); + + idx += row_width - 2; + for(int j=0; j<4; j++) { + ascii_img[idx + j] = buf[j]; + } + } + + // Add endlines to rows + for(int k = 0; k < n_rows; k++) { + idx = row_width * (k+1) - 1; + //std::cerr << "Adding endline " << k << ") --> " << idx << std::endl; + ascii_img[idx] = '\n'; + } + + // Terminate with null char + //std::cerr << "Adding 0 at end of char array" << std::endl; + ascii_img[n_pix - 1] = 0; + + // Print and cleanup + //std::cerr << "Printing char" << std::endl; + out << ascii_img << "\n"; + + //std::cerr << "done with ascii art" << std::endl; + + delete[] ascii_img; + + //std::cerr << "done with ascii art cleanup" << std::endl; } +const int N_PROPOSAL_TYPES = 6; +const int STEP_PROPOSAL = 0; +const int SWAP_PROPOSAL = 1; +const int SHIFT_L_PROPOSAL = 2; +const int SHIFT_R_PROPOSAL = 3; +const int SHIFT_ABS_L_PROPOSAL = 4; +const int SHIFT_ABS_R_PROPOSAL = 5; -double* TLOSMCMCParams::get_line_int(unsigned int thread_num) { - assert(thread_num < N_threads); - return line_int + img_stack->N_images * thread_num; + +struct DiscreteProposal { + // DiscreteProposal(gsl_rng* r); + void roll(gsl_rng* r); + void set(bool _step, bool _swap, bool _shift, + bool _left, bool _absolute, int _code); + bool step, swap, shift, left, absolute; + int code; +}; + +void DiscreteProposal::set(bool _step, bool _swap, bool _shift, + bool _left, bool _absolute, int _code) +{ + step = _step; + swap = _swap; + shift = _shift; + left = _left; + absolute = _absolute; + code = _code; } -float* TLOSMCMCParams::get_Delta_EBV(unsigned int thread_num) { - assert(thread_num < N_threads); - return Delta_EBV + (N_regions+1) * thread_num; +void DiscreteProposal::roll(gsl_rng* r) { + int p = gsl_rng_uniform_int(r, 12); + if(p < 4) { + set(true, false, false, false, false, STEP_PROPOSAL); + } else if(p < 8) { + set(false, true, false, false, false, SWAP_PROPOSAL); + } else if(p == 8) { + set(false, false, true, true, false, SHIFT_L_PROPOSAL); + } else if(p == 9) { + set(false, false, true, false, false, SHIFT_R_PROPOSAL); + } else if(p == 10) { + set(false, false, true, true, true, SHIFT_ABS_L_PROPOSAL); + } else { + set(false, false, true, false, true, SHIFT_ABS_R_PROPOSAL); + } +} + + +// Propose to take a step up or down in one pixel +void discrete_propose_step(gsl_rng* r, int n_x, int& x_idx, int& dy) { + x_idx = gsl_rng_uniform_int(r, n_x); // Random distance bin: [0, nx-1] + dy = 2 * gsl_rng_uniform_int(r, 2) - 1; // Step up or down one unit +} + + +// Propose to swap differential reddening btw/ two neighboring distance bins +void discrete_propose_swap(gsl_rng* r, int n_x, int& x_idx) { + // Random distance bin: [1, nx-2] + x_idx = gsl_rng_uniform_int(r, n_x-2) + 1; +} + + +// Propose to take a shift step up or down in all pixels beyond +// a certain distance +void discrete_propose_shift(gsl_rng* r, int n_x, int& x_idx, int& dy) { + x_idx = gsl_rng_uniform_int(r, n_x-1); // Random distance bin: [0, nx-2] + dy = 2 * gsl_rng_uniform_int(r, 2) - 1; // Step up or down one unit +} + + +double gen_exponential_variate(gsl_rng* r, double lambda, double tau) { + double u = gsl_rng_uniform(r); + // std::cerr << u << std::endl; + // std::cerr << " -lambda*tau = " << -lambda * tau << std::endl; + // std::cerr << " lambda = " << lambda << std::endl; + return -log(1. - (1. - exp(-lambda * tau)) * u) / lambda; +} + + +// double p_exponential(double x, double lambda) { +// return exp(-lambda * x); +// } + + +void discrete_propose_shift_abs( + gsl_rng* r, + int16_t* y_idx, + int n_x, + double y_mean, + double y_max, + int& x_idx, + int& dy, + double& ln_proposal_factor +) { + x_idx = gsl_rng_uniform_int(r, n_x-1); // Random distance bin: [0, nx-2] + double lambda = 1. / y_mean; + int y = (int)gen_exponential_variate(r, lambda, y_max); + // if((y < 0) || (y >= 700)) { + // std::cerr << "y = " << y << std::endl; + // std::exit(1); + // } + // if((x_idx < 0) || (x_idx > n_x-2)) { + // std::cerr << "x = " << x_idx << std::endl; + // std::exit(1); + // } + dy = y - y_idx[x_idx]; + ln_proposal_factor = lambda * dy; +} + + +// Checks whether a proposal lands in a valid region of parameter space +bool discrete_proposal_valid( + DiscreteProposal& proposal_type, + int y_idx_new, int n_y, + TDiscreteLosMcmcParams& params, + int x_idx, int dy, const int16_t *const y_idx_los_old) +{ + // STEP_PROPOSAL or SWAP_PROPOSAL + if(!proposal_type.shift) { + return (y_idx_new >= 0) && (y_idx_new < n_y); + } else if(proposal_type.left) { + // SHIFT_L_PROPOSAL or SHIFT_ABS_L_PROPOSAL + return params.shift_l_step_valid(x_idx, dy, y_idx_los_old); + } else { + // SHIFT_R_PROPOSAL or SHIFT_ABS_R_PROPOSAL + return params.shift_r_step_valid(x_idx, dy, y_idx_los_old); + } +} + + +void sample_los_extinction_discrete( + const std::string& out_fname, + const std::string& group_name, + TMCMCOptions& options, + TDiscreteLosMcmcParams& params, + const std::vector& neighbor_sample, + const TDiscreteLOSSamplingSettings& s, + int verbosity) +{ + std::cerr << "Beginning to sample discrete l.o.s. model ..." << std::endl; + + // + // Parallel tempering parameters + // + // -> Taken from TDiscreteSamplingSettings& s + + // + // Stellar PDF image parameters + // + int n_x = params.img_stack->rect->N_bins[1]; // # of distance pixels + int n_y = params.img_stack->rect->N_bins[0]; // # of reddening pixels + int n_stars = params.img_stack->N_images; // # of stars + + // + // Derived sampling parameters + // + int save_every = s.n_swaps / s.n_save; // Save one sample every # of swaps + int save_in = save_every; // Counts down until next saved sample + int n_saved = 0; + + int n_swaps_burnin = s.burnin_frac * s.n_swaps; + int n_swaps = s.n_swaps + n_swaps_burnin; + int central_steps_per_update = s.central_steps_per_update * n_x; + + if(verbosity >= 2) { + std::cerr << "Total # of central steps: " + << n_swaps + * s.updates_per_swap + * central_steps_per_update + << std::endl; + } + + //int n_steps = options.steps * n_x; + //int n_burnin = 0.25 * n_steps; + + //int n_neighbor_steps = 500; // TODO: Make this adjustable? + //int neighbor_step_every = n_steps / n_neighbor_steps; + //int neighbor_step_in = 1; + // + //int n_save = 500; + //int save_every = n_steps / n_save; + //int save_in = save_every; + + // How often to recalculate exact line integrals + int recalculate_every = 1000; + std::vector recalculate_in(s.n_temperatures, recalculate_every); + + // GSL random number generator + gsl_rng *r; + seed_gsl_rng(&r); + + // Temperature ladder + std::vector beta; + beta.reserve(s.n_temperatures); + double b = 1.0; + for(int t=0; t shift_weight_ladder; + shift_weight_ladder.reserve(s.n_temperatures); + double ln_sw_min = s.log_shift_weight_min; + double ln_sw_max = s.log_shift_weight_max; + if(s.shift_weight_ladder_logarithmic) { + double dlnsw = (ln_sw_max - ln_sw_min) / (s.n_temperatures - 1); + double ln_sw = ln_sw_min; + for(int t=0; t= 1) { + std::cerr << "shift_weight_" << t << " = " << sw << std::endl; + } + } + } else { + double sw_min = std::exp(ln_sw_min); + double sw_max = std::exp(ln_sw_max); + double dsw = (sw_max - sw_min) / (s.n_temperatures - 1); + double sw = sw_min; + for(int t=0; t= 1) { + std::cerr << "shift_weight_" << t << " = " << sw << std::endl; + } + } + } + + // Temporary variables + std::vector log_p(s.n_temperatures, 0.); + std::vector logPr(s.n_temperatures, 0.); + std::vector logL(s.n_temperatures, 0.); + double dlog_p; + //double log_p = 0; + //double logL = 0; + //double logPr = 0; + double ln_proposal_factor = 0; + + // + // Temporary variables for line integrals, etc. + // + std::vector>> line_int; + std::vector delta_line_int(n_stars, 0.); + line_int.reserve(s.n_temperatures); + for(int t=0; t>(n_stars, 0.) + ); + } + std::vector line_int_test(n_stars, 0.); + //std::vector line_int_test_old(n_stars, 0.); + + //double* line_int = new double[n_stars]; + //double* delta_line_int = new double[n_stars]; + + //double* line_int_test = new double[n_stars]; + //double* line_int_test_old = new double[n_stars]; + + // Calculate line integrals with correct line-of-sight distribution + // int16_t* y_idx_true = new int16_t[n_x]; + // double* line_int_true = new double[n_stars]; + // + // for(int j=0; j<24; j++) { + // y_idx_true[j] = 0; + // } + // for(int j=24; j<72; j++) { + // y_idx_true[j] = 100; + // } + // for(int j=72; j>> y_idx; + std::vector y_idx_dbl(n_x, 0.); + y_idx.reserve(s.n_temperatures); + for(int t=0; t>(n_x, 0) + ); + // Guess reddening profile + params.guess_EBV_profile_discrete(y_idx.at(0)->data(), r); + } else { + y_idx.push_back( + std::make_unique>( + y_idx.at(0)->begin(), + y_idx.at(0)->end() + ) + ); + } + } + //int16_t* y_idx = new int16_t[n_x]; + //double* y_idx_dbl = new double[n_x]; + //params.guess_EBV_profile_discrete(y_idx, r); + + // Calculate initial line integral for each star + std::cerr << "Calculate initial line integral for each star" << std::endl; + params.los_integral_discrete( + y_idx.at(0)->data(), + line_int.at(0)->data() + ); + for(int t=1; tat(s) = line_int.at(0)->at(s); + } + } + + // params.los_integral_discrete(y_idx, line_int_test_old); + + // for(int k = 0; k < n_x; k++) { + // y_idx_dbl[k] = (double)(y_idx[k]); + // } + + // Number of steps, samples to save, etc. + //int n_steps = options.steps * n_x; + //int n_burnin = 0.25 * n_steps; + + //int n_neighbor_steps = 500; // TODO: Make this adjustable? + //int neighbor_step_every = n_steps / n_neighbor_steps; + //int neighbor_step_in = 1; + // + //int s.n_save = 500; + //int save_every = n_steps / n_save; + //int save_in = save_every; + + // Acceptance statistics + int64_t n_proposals[] = {0, 0, 0, 0, 0, 0}, + n_proposals_accepted[] = {0, 0, 0, 0, 0, 0}, + n_proposals_valid[] = {0, 0, 0, 0, 0, 0}; + + // Chain + int n_save_buffered = 1.1*s.n_save + 5; // Number to save, + some margin + + std::vector> chain; + chain.push_back(std::make_unique(n_x, n_save_buffered)); + if(s.save_all_temperatures) { + for(int t=1; t(n_x, n_save_buffered)); + } + } + + // Neighboring pixels + //unsigned int n_temperatures = 4; + //double beta_spacing = 0.50; // Spacing of sampling temperatures (0>> neighbor_sample; + //std::vector beta; // Temperature of each neighbor sampler + + // + // Information on neighboring pixels + // + + // Quantities needed for calculation of marginal probabilities. + // One vector per temperature to save, so shape is: (temperature, sample) + std::vector> logL_chain, logPr_chain; + std::vector> y_idx_chain; + std::vector> neighbor_sample_chain; + int n_neighbors = 1; + int n_neighbor_samples = 1; + + // Maximum temperature to save + int t_save_max = 1; + if(s.save_all_temperatures) { + t_save_max = s.n_temperatures; + } + + if(params.neighbor_pixels) { + n_neighbors = params.neighbor_pixels->get_n_pix(); + n_neighbor_samples = params.neighbor_pixels->get_n_samples(); + + logL_chain.reserve(t_save_max); + logPr_chain.reserve(t_save_max); + y_idx_chain.reserve(t_save_max); + neighbor_sample_chain.reserve(t_save_max); + + for(int t=0; t n_swaps_proposed(s.n_temperatures-1, 0); + std::vector n_swaps_accepted(s.n_temperatures-1, 0); + + //if(params.neighbor_pixels) { + //double b = 1.0; + //beta.reserve(n_temperatures); + //log_p_neighbor.resize(n_temperatures); + + //for(int t=0; t>()); + // neighbor_sample.at(t)->reserve(params.neighbor_pixels->get_n_pix()); + // randomize_neighbors( + // *(params.neighbor_pixels), + // *neighbor_sample.at(t), + // params.r); + // (*(neighbor_sample.at(t)))[0] = 0; + + // beta.push_back(b); + //} + + //gibbs_order.reserve(params.neighbor_pixels->get_n_pix()-1); + //for(int i=1; iget_n_pix(); i++) { + // gibbs_order.push_back(i); + //} + //} + + // Pixel indices chosen for neighbors + std::vector>> neighbor_idx; + neighbor_idx.reserve(s.n_temperatures); + // log(prior) of neighboring pixel combination + std::vector logPr_neighbor(s.n_temperatures, 0.); + // Sampling order for neighboring pixels. Will be shuffled. + std::vector neighbor_gibbs_order; + // Workspaces used during neighbor pixel sampling + std::vector log_p_sample_ws; + std::vector p_sample_ws; + std::vector mu_ws; + // # of samples stored in neighboring pixels + + if(params.neighbor_pixels) { + for(int t=0; t>() + ); + neighbor_idx.at(t)->reserve(n_neighbors); + + // Initialize different temperatures to same staring position + if(t == 0) { + randomize_neighbors( + *(params.neighbor_pixels), + *(neighbor_idx.at(0)), + params.r + ); + // Central pixel always fixed to sample 0 for simplicity. + // Sampled line-of-sight profile will be copied in. + neighbor_idx.at(0)->at(0) = 0; + } else { + std::copy( + neighbor_idx.at(0)->begin(), + neighbor_idx.at(0)->end(), + std::back_inserter(*(neighbor_idx.at(t))) + ); + } + } + + log_p_sample_ws.resize(n_neighbor_samples); + p_sample_ws.resize(n_neighbor_samples); + + neighbor_gibbs_order.reserve(n_neighbors-1); + for(int n=1; n>( + n_neighbor_samples, + 0 + ) + ); + } + } + + // Priors on dE in central pixel + std::vector> lnP_dy; + lnP_dy.reserve(s.n_temperatures); + for(int t=0; t() + ); + params.update_priors_image( + *(lnP_dy.at(t)), + *(neighbor_idx.at(t)), + 0., + params.priors_subsampling, + shift_weight_ladder.at(t), + verbosity + ); + logPr.at(t) = params.log_prior( + y_idx.at(t)->data(), + *(lnP_dy.at(t)) + ); + } + + // Calculate initial prior + //std::cerr << "Calculate initial prior" << std::endl; + //logPr.at(0) = params.log_prior(y_idx.at(0)->data()); + //for(int t=1; tdata()); + //} + + // Random sampler to select temperature (excluding T=1) + std::uniform_int_distribution r_temperature(1, s.n_temperatures-1); + + //std::uniform_int_distribution r_neighbor( + // 0, + // neighbor_sample.size()/(n_neighbors+1) - 1 + //); + + // std::cerr << std::endl + // << "##################################" << std::endl + // << "n_x = " << n_x << std::endl + // << "n_y = " << n_y << std::endl + // << "n_stars = " << n_stars << std::endl + // << "n_steps = " << n_steps << std::endl + // << "##################################" << std::endl + // << std::endl; + // + + // Hash to speed up neighbor gibbs steps + #define USE_NEIGHBOR_GIBBS_CACHE 0 + #if USE_NEIGHBOR_GIBBS_CACHE + int gibbs_cache_capacity = 5000; + std::vector< + LRUCache::CachedFunction< + std::vector, + std::shared_ptr, + LRUCache::VectorHasher + > + > gibbs_step_cache; + + int gibbs_step_pix; + int disc_distr_res; + double lnp_cutoff_cache = -10.; + + std::vector< + std::function&)> + > roll_gibbs_idx; + + if(params.neighbor_pixels) { + gibbs_step_cache.reserve(s.n_temperatures); + roll_gibbs_idx.reserve(s.n_temperatures); + for(int t=0; t, + std::shared_ptr, + LRUCache::VectorHasher + >( + [ + &gibbs_step_pix, + &neighbor_pixels=*(params.neighbor_pixels), + &log_p_sample_ws, + &p_sample_ws, + &mu_ws, + bt=beta.at(t), + shift_weight_ladder.at(t), + lnp_cutoff_cache + ] + (const std::vector& nbor_idx) + -> std::shared_ptr + { + //uint16_t s_tmp = nbor_samp[step_pix]; + //nbor_samp[step_pix] = neighbor_pixels.get_n_pix(); + std::unique_ptr cache_entry = + neighbor_gibbs_step_shifted_cache_data( + gibbs_step_pix, + neighbor_pixels, + nbor_idx, + log_p_sample_ws, + p_sample_ws, + mu_ws, + bt, + shift_weight_ladder.at(t), + lnp_cutoff_cache + ); + //nbor_samp[step_pix] = s_tmp; + return std::move(cache_entry); + }, + gibbs_cache_capacity, + nullptr) + ); + + roll_gibbs_idx.push_back( + [ + &gibbs_step_pix, + &neighbor_pixels=*(params.neighbor_pixels), + &neighbor_idx, + &log_p_sample_ws, + &p_sample_ws, + &mu_ws, + bt=beta.at(t), + shift_weight_ladder.at(t), + lnp_cutoff_cache, + &rr=params.r, + &disc_distr_res, + t + ] + (std::shared_ptr& cache_entry) + -> void + { + disc_distr_res = neighbor_gibbs_step_shifted_cached( + gibbs_step_pix, + *cache_entry, + neighbor_pixels, + *(neighbor_idx.at(t)), + log_p_sample_ws, + p_sample_ws, + mu_ws, + bt, + shift_weight_ladder.at(t), + lnp_cutoff_cache, + rr + ); + } + ); + } + } + #endif + + //int w = 0; + + // Softening parameter + // TODO: Make p_badstar either a config option or dep. on ln(Z) + const floating_t p_badstar = s.p_badstar;//1.e-5; //0.0001; + const floating_t epsilon = p_badstar / (floating_t)n_y; + + double sigma_dy_neg = 1.e-5; + double sigma_dy_neg_target = 1.e-10; + double tau_decay = (double)n_swaps / 20.; + + // Proposal settings + // TODO: Set these more intelligently, or make them configurable? + // Mean value of y chosen in "absolute shift" proposals + double y_shift_abs_mean = n_y / 20; + // Maximum value of y chosen in "absolute shift" proposals + double y_shift_abs_max = n_y; + + // uint64_t n_eval_diff = 0; + // uint64_t n_eval_cumulative = 0; + // uint64_t n_shift_steps = 0; + + DiscreteProposal proposal_type; + + std::uniform_real_distribution<> uniform_dist(0., 1.0); + + auto t_start = std::chrono::steady_clock::now(); + + // Loop over swaps between temperatures + for(int swap=0; swapdata(); + double* line_int_t = line_int.at(t)->data(); + double& logPr_t = logPr.at(t); + double& logL_t = logL.at(t); + double& log_p_t = log_p.at(t); + cv::Mat& lnP_dy_t = *(lnP_dy.at(t)); + double b = beta.at(t); + + // Loop over update cycles + for(int u=0; uat(k) = n_neighbor_samples; + gibbs_step_pix = k; + gibbs_step_cache.at(t)( + *(neighbor_idx[t]), + roll_gibbs_idx.at(t) + ); + neighbor_idx[t]->at(k) = disc_distr_res; + #else + neighbor_gibbs_step_shifted( + k, + *(params.neighbor_pixels), + *(neighbor_idx[t]), + log_p_sample_ws, + p_sample_ws, + params.r, + b, + shift_weight_ladder.at(t) + ); + #endif + } + } + + // Update priors on central + params.update_priors_image( + lnP_dy_t, + *(neighbor_idx.at(t)), + 0., + params.priors_subsampling, + shift_weight_ladder.at(t), + verbosity + ); + logPr_t = params.log_prior(y_idx_t, lnP_dy_t); + log_p_t = logPr_t + logL_t; + } + + // Between neighbor updates, update central pixel + for(int c=0; cget_n_pix(); j++) { + std::cerr << " " << neighbor_idx.at(tt)->at(j); + } + std::cerr << std::endl; + } + + for(int tt=0; ttget_n_pix(); j++) { + dist_max = params.neighbor_pixels->get_dominant_dist( + j, + neighbor_idx.at(tt)->at(j) + ); + std::cerr << " " << dist_max; + } + std::cerr << std::endl; + } + } + + std::cerr << "log(p)_t ="; + for(int t=0; t t_elapsed = t_now - t_start; + std::cerr << std::endl; + ascii_progressbar( + swap, + n_swaps, + 50, + t_elapsed.count(), + std::cerr + ); + std::cerr << std::endl; + } + + // Attempt swap + if(s.n_temperatures > 1) { + // Choose temperature pair to swap + int t1 = r_temperature(params.r); // 1 <= t1 <= n_temperatures-1 + int t0 = t1 - 1; + + n_swaps_proposed[t0]++; + + // Determine probability density of each temperature + + // First, calculate the prior at each temperature + double logPr_x1s1, logPr_x0s0; + double logPr_x1s0, logPr_x0s1; + + if(params.neighbor_pixels) { + params.set_central_delta(y_idx.at(t1)->data()); + logPr_x1s1 = params.neighbor_pixels->calc_lnprob_shifted( + *(neighbor_idx.at(t1)), + shift_weight_ladder.at(t1), + false + ); + logPr_x1s0 = params.neighbor_pixels->calc_lnprob_shifted( + *(neighbor_idx.at(t1)), + shift_weight_ladder.at(t0), + false + ); + + params.set_central_delta(y_idx.at(t0)->data()); + logPr_x0s0 = params.neighbor_pixels->calc_lnprob_shifted( + *(neighbor_idx.at(t0)), + shift_weight_ladder.at(t0), + false + ); + logPr_x0s1 = params.neighbor_pixels->calc_lnprob_shifted( + *(neighbor_idx.at(t0)), + shift_weight_ladder.at(t1), + false + ); + } else { + logPr_x1s1 = params.log_prior( + y_idx.at(t1)->data(), + *(lnP_dy.at(t1)) + ); + logPr_x1s0 = params.log_prior( + y_idx.at(t1)->data(), + *(lnP_dy.at(t0)) + ); + logPr_x0s0 = params.log_prior( + y_idx.at(t0)->data(), + *(lnP_dy.at(t0)) + ); + logPr_x0s1 = params.log_prior( + y_idx.at(t0)->data(), + *(lnP_dy.at(t1)) + ); + } + + // Next, add in the likelihoods + double logL_t0 = logL.at(0); + double logL_t1 = logL.at(1); + //logp_t1 += logL.at(t1); + //logp_t0 += logL.at(t0); + + if(params.neighbor_pixels) { + for(int neighbor=1; neighborget_likelihood( + neighbor, + neighbor_idx.at(t1)->at(neighbor) + ); + logL_t0 += params.neighbor_pixels->get_likelihood( + neighbor, + neighbor_idx.at(t0)->at(neighbor) + ); + } + } + + // Acceptance likelihood term + double alpha_L = (beta.at(t1) - beta.at(t0)) + * (logL_t0 - logL_t1); + + // Acceptance prior term + double alpha_Pr = beta.at(t0) * (logPr_x1s0 - logPr_x0s0) + + beta.at(t1) * (logPr_x0s1 - logPr_x1s1); + + double alpha = alpha_L + alpha_Pr; + //alpha = -9999.; // TODO: remove this line + + if(verbosity >= 2) { + std::cerr << "Swap " << t1-1 << " <-> " << t1 + << std::endl + << " alpha_L = " << alpha_L + << std::endl + << " alpha_Pr = " << alpha_Pr + << std::endl + << " logPr_x0s1 - logPr_x0s0 = " << logPr_x0s1 - logPr_x0s0 + << std::endl + << " logPr_x1s0 - logPr_x1s1 = " << logPr_x1s0 - logPr_x1s1 + << std::endl + << " alpha = " << alpha; + } + + if((alpha > 0.) + || ( + (alpha > -10.) && + (std::exp(alpha) > gsl_rng_uniform(r)) + )) + { + // Swap accepted + n_swaps_accepted[t0]++; + + // Swap all the relevant pointers + y_idx.at(t1).swap(y_idx.at(t0)); + line_int.at(t1).swap(line_int.at(t0)); + neighbor_idx.at(t1).swap(neighbor_idx.at(t0)); + lnP_dy.at(t1).swap(lnP_dy.at(t0)); + + // Swap all the relevant values + std::swap(logL.at(t1), logL.at(t0)); + logPr.at(t1) = logPr_x0s1; + logPr.at(t0) = logPr_x1s0; + log_p.at(t0) = logL.at(t0) + logPr.at(t0); + log_p.at(t1) = logL.at(t1) + logPr.at(t1); + + if(verbosity >= 2) { + std::cerr << " (accepted)"; + } + } + + if(verbosity >= 2) { std::cerr << std::endl; } + } + } // s (swaps) + + //for(int i = 0; i < n_steps + n_burnin; i++) { + // // Randomize neighbors + // if(params.neighbor_pixels && (--neighbor_step_in == 0)) { + // neighbor_step_in = neighbor_step_every; + // + // //params.randomize_neighbors(neighbor_sample); + // //neighbor_sample[0] = 0; + + // // Gibbs sample neighboring pixels + // //params.set_central_delta(y_idx); + // //for(int t=1; tsize(); k++) { + // // (*(neighbor_sample[t]))[k] = (*(neighbor_sample[0]))[k]; + // // } + // //} + + // //for(int j=0; j " << t << std::endl; + // // neighbor_sample[t].swap(neighbor_sample[t-1]); + // // n_swaps_accepted++; + // // } else { + // // //std::cerr << "no swap " << t-1 << " <-> " << t << std::endl; + // // } + // // } + // //} + + // // Update the pre-computed priors image, in (E, DM)-pixel-space + // //params.update_priors_image( + // // *(neighbor_sample.at(0)), 0., + // // params.priors_subsampling, + // // verbosity); + // + // int idx = r_neighbor(params.r); + // neighbor_idx.push_back(idx); + + // neighbor_sample_ws.clear(); + // neighbor_sample_ws.insert( + // neighbor_sample_ws.end(), + // neighbor_sample.begin() + (n_neighbors+1)*idx, + // neighbor_sample.begin() + (n_neighbors+1)*(idx+1) + // ); + + // params.update_priors_image( + // neighbor_sample_ws, 0., + // params.priors_subsampling, + // verbosity); + + // // Update log(prior) of current state + // logPr = params.log_prior(y_idx); + // } + // + // // Smoothly ramp penalty on negative reddening steps up + // sigma_dy_neg -= (sigma_dy_neg - sigma_dy_neg_target) / tau_decay; + // params.inv_sigma_dy_neg = 1. / sigma_dy_neg; + + // // Increase weight of current state + // w += 1; + + // // Propose a new state + // int x_idx, dy, y_idx_new, dy1; + + // // Determine what type of proposal to make + // proposal_type.roll(r); + // // int proposal_type = gsl_rng_uniform_int(r, N_PROPOSAL_TYPES); + // // int proposal_type = STEP_PROPOSAL; + // // int proposal_type; + // // double prop_rand = gsl_rng_uniform(r); + // // const double p_swap = 0.8; + // // const double p_step = 0.1; + // // // const double p_shift = 0.1; + // // if(prop_rand < p_swap) { + // // proposal_type = SWAP_PROPOSAL; + // // } else if(prop_rand < p_swap + p_step) { + // // proposal_type = STEP_PROPOSAL; + // // } else { + // // proposal_type = SHIFT_PROPOSAL; + // // } + + // n_proposals[proposal_type.code]++; + + // if(proposal_type.step) { + // discrete_propose_step(r, n_x, x_idx, dy); + // y_idx_new = y_idx[x_idx] + dy; + // } else if(proposal_type.swap) { + // discrete_propose_swap(r, n_x, x_idx); + // dy1 = y_idx[x_idx+1] - y_idx[x_idx]; + // y_idx_new = y_idx[x_idx-1] + dy1; + // } else if(proposal_type.absolute) { + // // SHIFT_ABS_L_PROPOSAL or SHIFT_ABS_R_PROPOSAL + // discrete_propose_shift_abs( + // r, y_idx, n_x, y_shift_abs_mean, y_shift_abs_max, + // x_idx, dy, ln_proposal_factor + // ); + // } else { + // // SHIFT_L_PROPOSAL or SHIFT_R_PROPOSAL + // discrete_propose_shift(r, n_x, x_idx, dy); + // } + + // // int y_idx_new = y_idx[x_idx] + dy; + + // // Check if the proposal lands in a valid region of parameter space + // bool prop_valid = discrete_proposal_valid( + // proposal_type, y_idx_new, n_y, + // params, x_idx, dy, y_idx); + + // if(prop_valid) { + // n_proposals_valid[proposal_type.code]++; + + // double dlogL = 0; + // double dlogPr, alpha; + + // // Calculate difference in line integrals and prior (between the + // // current and proposed states). + // if(proposal_type.step) { + // params.los_integral_diff_step( + // x_idx, + // y_idx[x_idx], + // y_idx_new, + // delta_line_int + // ); + // dlogPr = params.log_prior_diff_step(x_idx, y_idx, y_idx_new); + // } else if(proposal_type.swap) { + // params.los_integral_diff_swap( + // x_idx, y_idx, + // delta_line_int + // ); + // dlogPr = params.log_prior_diff_swap(x_idx, y_idx); + // } else if(proposal_type.left) { + // dlogPr = params.log_prior_diff_shift_l(x_idx, dy, y_idx); + // // No point in calculating line integrals if prior -> -infinity. + // if(dlogPr != -std::numeric_limits::infinity()) { + // params.los_integral_diff_shift_l( + // x_idx, dy, y_idx, + // delta_line_int + // ); + // } + + // // std::cerr << dlogPr << std::endl; + // } else { // SHIFT_R_PROPOSAL or SHIFT_ABS_R_PROPOSAL + // dlogPr = params.log_prior_diff_shift_r(x_idx, dy, y_idx); + + // // if(x_idx == 0) { + // // std::cerr << "shift(0, " + // // << y_idx[0] << " -> " << y_idx[0] + dy + // // << ") : dln(prior) = " << dlogPr + // // << std::endl; + // // } + + // // No point in calculating line integrals if prior -> -infinity. + // if(dlogPr != -std::numeric_limits::infinity()) { + // params.los_integral_diff_shift_r( + // x_idx, dy, y_idx, + // delta_line_int + // ); + + // // unsigned int n_eval_diff_tmp; + // // unsigned int n_eval_cumulative_tmp; + // // params.los_integral_diff_shift_compare_operations( + // // x_idx, dy, y_idx, + // // n_eval_diff_tmp, + // // n_eval_cumulative_tmp + // // ); + // // + // // n_eval_diff += n_eval_diff_tmp; + // // n_eval_cumulative += n_eval_cumulative_tmp; + // // n_shift_steps++; + + + // } + // } + + // // Change in likelihood + // if(dlogPr != -std::numeric_limits::infinity()) { + // for(int k = 0; k < n_stars; k++) { + // double zeta = delta_line_int[k] / (line_int[k]+epsilon); + // if(std::fabs(zeta) < 1.e-2) { + // dlogL += zeta - 0.5 * zeta*zeta + 0.33333333*zeta*zeta*zeta; // Taylor expansion of log(1+zeta) for zeta << 1. + // } else { + // dlogL += std::log(1.0 + zeta); + // } + // } + // } + + // // Acceptance probability + // alpha = dlogL + dlogPr; + // //alpha = dlogPr; // TODO: Switch back to log(prior) + log(likelihood) + + // if(proposal_type.absolute) { + // alpha += ln_proposal_factor; + // } + + // // Accept proposal? + // if((alpha > 0) || ((alpha > -10.) && (std::exp(alpha) > gsl_rng_uniform(r)))) { + // // if((dlogPr < -10000) || (dlogPr > 10000)) { + // // std::cerr << "dlogPr = " << dlogPr << std::endl + // // << " proposal_type = " << proposal_type << std::endl + // // << " x_idx = " << x_idx << std::endl + // // << " dy = " << dy << std::endl + // // << " y_idx[0] = " << y_idx[0] << std::endl; + // // std::exit(1); + // // } + + // // ACCEPT + // n_proposals_accepted[proposal_type.code]++; + + // // Add old point to chain + // // chain.add_point(y_idx_dbl, log_p, (double)w); + + // // Update state to proposal + // if(!proposal_type.shift) { + // // STEP_PROPOSAL or SWAP_PROPOSAL + // y_idx[x_idx] = y_idx_new; + // // y_idx_dbl[x_idx] = (double)y_idx_new; + // } else if(proposal_type.left) { + // for(int j=0; j<=x_idx; j++) { + // y_idx[j] += dy; + // } + // } else { // SHIFT_R_PROPOSAL or SHIFT_ABS_R_PROPOSAL + // for(int j=x_idx; j 0.001) { + // // std::cerr << "x_idx = " << x_idx << std::endl; + // // std::exit(1); + // // } + + // // params.los_integral_discrete(y_idx, line_int_test); + + // // for(int k=0; k 1.e-10) { + // // floating_t P_old = params.img_stack->img[k]->at( + // // y_idx_new-dy, x_idx); + // // floating_t P_new = params.img_stack->img[k]->at( + // // y_idx_new, x_idx); + // // + // // std::cerr << "delta_resid[" << k << "] = " + // // << delta_resid + // // << " , delta = " + // // << delta_true + // // << " , integral = " + // // << line_int_test[k] + // // << " , x_idx = " + // // << x_idx + // // << std::endl; + // // std::cerr << " P_old = " << P_old << std::endl + // // << " P_new = " << P_new << std::endl + // // << " P_new - P_old = " << P_new - P_old << std::endl; + // // } + // // // std::cerr << delta_true << " " << rel_delta_resid << std::endl; + // // } + + // // std::swap(line_int_test, line_int_test_old); + + // // Reset weight to zero + // w = 0; + // } + // } + + // // Add state to chain + // if((i >= n_burnin) && (--save_in == 0)) { + // for(int k=0; k= 2) && (i % 10000 == 0)) { + // discrete_los_ascii_art( + // n_x, n_y, y_idx, + // 40, 700, + // params.img_stack->rect->dx[0], + // 4., 19., + // std::cerr); + // std::cerr << std::endl; + + // params.los_integral_discrete(y_idx, line_int_test); + // double abs_resid_max = -std::numeric_limits::infinity(); + // double rel_resid_max = -std::numeric_limits::infinity(); + // for(int k=0; kget_n_pix(); j++) { + // std::cerr << " " << neighbor_sample_ws.at(j); + // } + // std::cerr << std::endl << std::endl; + // } + + // // std::vector> delta_line_int_true; + // // double delta_lnL_true = 0.; + // // for(int k=0; k _l, std::pair _r) -> bool { + // // return _l.second < _r.second; + // // } + // // ); + // // + // // std::cerr << "Delta ln(L) = " << delta_lnL_true << std::endl; + // // int n_show = 4; + // // for(int k=0; k t_elapsed = t_now - t_start; + // ascii_progressbar(i, n_steps+n_burnin, 50, t_elapsed.count(), std::cerr); + // std::cerr << std::endl; + // } + //} + + if(verbosity >= 1) { + std::string prop_name[N_PROPOSAL_TYPES]; + prop_name[STEP_PROPOSAL] = "step"; + prop_name[SWAP_PROPOSAL] = "swap"; + prop_name[SHIFT_L_PROPOSAL] = "shift_l"; + prop_name[SHIFT_R_PROPOSAL] = "shift_r"; + prop_name[SHIFT_ABS_L_PROPOSAL] = "shift_abs_l"; + prop_name[SHIFT_ABS_R_PROPOSAL] = "shift_abs_r"; + + uint64_t n_proposals_tot = 0; + for(int i=0; i= 2) { + std::cerr << std::endl + << "Estimating p(alpha_central) ..." + << std::endl; + } + + auto t_start_marg = std::chrono::steady_clock::now(); + + int16_t* chain_ptr = y_idx_chain.at(0).data(); + int chain_len = logL_chain.at(0).size(); + + // For each temperature, p(alpha_t|neighbors_0) for all + // samples alpha_t from temperature t, and all neighbors + // from the temperature=1 chain. + // shape = (temperature, (chain sample, neighbor sample)) + std::vector> prior_chain; + for(int t=0; t prior_avg(chain_len, 0.); + std::vector neighbor_sample_ws; + neighbor_sample_ws.resize(n_neighbors); + neighbor_sample_ws[0] = 0; + + // For each set of neighbor pixels + for(int i=0; i::quiet_NaN(), // ln(Z) + NULL, // Gelman-Rubin statistic + false // subsample + ); + } + + chain_write_buffer.write(out_fname, group_name, "discrete-los"); + + std::stringstream dset_name; + dset_name << group_name << "/discrete-los"; + + double dm_min = params.img_stack->rect->min[1]; + double dm_max = params.img_stack->rect->max[1]; + H5Utils::add_watermark( + out_fname, + dset_name.str(), + "DM_min", + dm_min + ); + H5Utils::add_watermark( + out_fname, + dset_name.str(), + "DM_max", + dm_max + ); + + auto t_end = std::chrono::steady_clock::now(); + std::chrono::duration t_runtime = t_end - t_start; + H5Utils::add_watermark( + out_fname, + dset_name.str(), + "runtime", + t_runtime.count() + ); + + gsl_rng_free(r); +} + + +//void propose_neighbor_dominant_dist_swap( +// TNeighborPixels& neighbor_pixels, +// const std::vector& samples, +// std::vector& prop_samples, +// int verbosity) +//{ +// // Look up dominant distance of each pixel +// std::vector d_curr; +// d_curr.reserve(n_pix); +// for(int pix=0; pix& chain, + int verbosity) +{ + // Sampling parameters + unsigned int n_temperatures = 5; + double beta_spacing = 0.70; // Spacing of sampling temperatures (0 uniform_dist(0., 1.0); + + // For each temperature, which sample to select for each neighboring pix + std::vector>> neighbor_sample; + std::vector beta; // Temperature of each neighbor sampler + std::vector gibbs_order; // Order in which to update neighboring pixels + std::vector temp_order; // Order in which to swap between temperatures + std::vector log_p_neighbor; + std::vector n_swaps_proposed(n_temperatures-1, 0); + std::vector n_swaps_accepted(n_temperatures-1, 0); + + // Initialize temperature ladder + double b = 1.0; + beta.reserve(n_temperatures); + log_p_neighbor.resize(n_temperatures); + + for(int t=0; t>()); + neighbor_sample.at(t)->reserve(neighbor_pixels.get_n_pix()); + + if(t == 0) { + randomize_neighbors( + neighbor_pixels, + *neighbor_sample.at(0), + r + ); + } else { + std::copy( + neighbor_sample.at(0)->begin(), + neighbor_sample.at(0)->end(), + std::back_inserter(*(neighbor_sample.at(t))) + ); + } + + //(*(neighbor_sample.at(t)))[0] = 0; + + beta.push_back(b); + + log_p_neighbor.at(t) = 0.; + } + + // Initialize Gibbs sampling order + gibbs_order.reserve(neighbor_pixels.get_n_pix()); + for(int i=0; i sample_chain; + //TChain chain(n_dim, n_save+1); + + // Likelihood and prior of samples + std::vector logL_chain, logPr_chain; + + int n_pix = neighbor_pixels.get_n_pix(); + int n_samples = neighbor_pixels.get_n_samples(); + + logL_chain.reserve(n_save+1); + logPr_chain.reserve(n_save+1); + sample_chain.reserve(n_pix*n_save); + + std::vector log_p_sample_ws; + std::vector p_sample_ws; + log_p_sample_ws.resize(n_samples); + p_sample_ws.resize(n_samples); + + // Clear output chain + chain.clear(); + + + // Cache Gibbs-step samplers + uint64_t cache_capacity = 10000; + int step_pix; + std::vector< + LRUCache::CachedFunction< + std::vector, + std::shared_ptr>, + LRUCache::VectorHasher + > + > gibbs_step_cache; + gibbs_step_cache.reserve(n_temperatures); + for(int t=0; t, + std::shared_ptr>, + LRUCache::VectorHasher + >( + [ + &step_pix, + &neighbor_pixels, + &log_p_sample_ws, + &p_sample_ws, + bt=beta.at(t), + shift_weight + ] + (const std::vector& nbor_samp) + -> std::shared_ptr> + { + //uint16_t s_tmp = nbor_samp[step_pix]; + //nbor_samp[step_pix] = neighbor_pixels.get_n_pix(); + std::unique_ptr> dd = + neighbor_gibbs_step_shifted_factory( + step_pix, + neighbor_pixels, + nbor_samp, + log_p_sample_ws, + p_sample_ws, + bt, + shift_weight + ); + //nbor_samp[step_pix] = s_tmp; + return std::move(dd); + }, + cache_capacity, + nullptr) + ); + } + + int disc_distr_res; + auto roll_disc_distr = [&r, &disc_distr_res]( + std::shared_ptr>& dd + ) -> void + { + disc_distr_res = (*dd)(r); + }; + + // ln(p) cache + LRUCache::CachedFunction< + std::vector, + double, + LRUCache::VectorHasher + > lnp_cache( + [ + &neighbor_pixels, + shift_weight + ](const std::vector& nbor_samp) -> double { + return neighbor_pixels.calc_lnprob_shifted( + nbor_samp, + shift_weight + ); + }, + cache_capacity + ); + + // Sample + for(int j=0; j= 2) { + std::cerr << "Swap " << j+1 << " of " << n_swaps_tot << std::endl; + } + + for(int t=0; tat(k); + neighbor_sample[t]->at(k) = n_pix; + step_pix = k; + gibbs_step_cache.at(t)( + *(neighbor_sample[t]), + roll_disc_distr + ); + neighbor_sample[t]->at(k) = disc_distr_res; + //log_p_neighbor[t] += neighbor_gibbs_step_shifted( + // k, + // neighbor_pixels, + // *(neighbor_sample[t]), + // log_p_sample_ws, + // p_sample_ws, + // r, + // beta.at(t), + // shift_weight + //); + } + } + + // Recalculate log(p) of this temperature + log_p_neighbor[t] = lnp_cache(*(neighbor_sample.at(t))); + //log_p_neighbor[t] = neighbor_pixels.calc_lnprob_shifted( + // *(neighbor_sample.at(t)), + // shift_weight + //); + } + + std::cerr << "log_p:"; + for(int t=0; t " << t << std::endl; + neighbor_sample[t].swap(neighbor_sample[t-1]); + + double tmp = log_p_neighbor[t-1]; + log_p_neighbor[t-1] = log_p_neighbor[t]; + log_p_neighbor[t] = tmp; + + n_swaps_accepted.at(t-1)++; + } else { + //std::cerr << "no swap " << t-1 << " <-> " << t << std::endl; + } + } + + if((j >= n_swaps_burnin) && (--save_in == 0)) { + save_in = save_every; + + // Save point + //sample_chain.insert( + // sample_chain.end(), + // neighbor_sample.at(0)->begin(), + // neighbor_sample.at(0)->end() + //); + chain.insert( + chain.end(), + neighbor_sample.at(0)->begin(), + neighbor_sample.at(0)->end() + ); + + // Calculate ln(p) + double lnP = neighbor_pixels.calc_lnprob(*(neighbor_sample.at(0))); + + //chain.add_point(neighbor_sample.at(0)->data(), lnP, 1.); + + if(verbosity >= 2) { + for(int t=0; t " << lnP; + std::cerr << std::endl; + + int dist_max; + for(int pix=0; pixat(pix) + ); + std::cerr << " " << dist_max; + } + std::cerr << std::endl; + } + std::cerr << std::endl; + } + + if(j == n_swaps_burnin) { + for(int t=0; t= 1) { + double swap_pct; + std::cerr << "Swap acceptance %:"; + for(int t=0; t::quiet_NaN(), // ln(Z) + // NULL, // Gelman-Rubin statistic + // false // subsample + //); + //chain_write_buffer.write(out_fname, group_name, "neighbor_samples"); + +} + + +void seed_prng(std::mt19937& r) { + // Seeds a pseudo-random number generator from the stdlib, using + // both the system's random device and the high-resolution clock. + + std::random_device rd; + std::vector seeds = { + rd(), + static_cast( + std::chrono::high_resolution_clock::now().time_since_epoch().count() + ) + }; + std::seed_seq seq(seeds.begin(), seeds.end()); + + r.seed(seq); } +void sample_neighbors( + TNeighborPixels& neighbors, + int verbosity) +{ + int n_burnin = 10000; + int n_steps = 100000; + + unsigned int n_samples_max = 50; + unsigned int n_samples = std::min(n_samples_max, neighbors.get_n_samples()); + + auto f_prob = [&neighbors](const std::vector& samp_idx) -> double { + return neighbors.calc_lnprob(samp_idx); + }; + + double lnp0 = 0.; + std::vector samp_idx_tmp; + samp_idx_tmp.resize(neighbors.get_n_pix()); + + // Pseudo-random number generator + std::random_device rd; + std::vector seeds = { + rd(), + static_cast(std::chrono::high_resolution_clock::now().time_since_epoch().count()) + }; + std::seed_seq seq(seeds.begin(), seeds.end()); + std::mt19937 r(seq); + + std::uniform_int_distribution d(0, n_samples-1); + + for(int n=0; n<100; n++) { + for(auto& s : samp_idx_tmp) { + s = d(r); + } + lnp0 += f_prob(samp_idx_tmp); + } + + lnp0 /= 100.; + lnp0 *= 0.5; + std::cout << "lnp0 = " << lnp0 << std::endl; + + bridgesamp::BridgingSampler sampler( + neighbors.get_n_pix(), + n_samples, + f_prob + ); + + sampler.set_logp0(lnp0 + 5.); + + sampler.randomize_state(); + + for(int i=0; ifirst) { + // if(s == neighbors.get_n_samples()) { + // std::cerr << "- "; + // } else { + // std::cerr << s << " "; + // } + // } + // std::cerr << ": " << it->second.logp << std::endl; + //} + + std::map, uint32_t> n_visits; + double logp_max = -std::numeric_limits::infinity(); + double logp; + + for(int n=0; n logp_max) { + logp_max = logp; + } + std::cout << "log(p) = " << logp << " (<= " << logp_max << " )" << std::endl; + std::cout << " " << 100.*sampler.fill_factor() << "%" << std::endl; + } + } + + // Print out the number of visits to each state + std::cout << "# of visits:" + << std::endl; + + for(auto& v : n_visits) { + for(auto s : v.first) { + if(s == sampler.get_n_samples()) { + std::cout << "- "; + } else { + std::cout << s << " "; + } + } + std::cout << ": " << v.second << std::endl; + } +} + /**************************************************************************************************************************** - * + * * TImgStack - * + * ****************************************************************************************************************************/ TImgStack::TImgStack(size_t _N_images) { - N_images = _N_images; - img = new cv::Mat*[N_images]; - for(size_t i=0; i &keep) { - assert(keep.size() == N_images); - - size_t N_tmp = 0; - for(std::vector::const_iterator it = keep.begin(); it != keep.end(); ++it) { - if(*it) { N_tmp++; } - } - - cv::Mat **img_tmp = new cv::Mat*[N_tmp]; - size_t i = 0; - size_t k = 0; - for(std::vector::const_iterator it = keep.begin(); it != keep.end(); ++it, ++i) { - if(*it) { - img_tmp[k] = img[i]; - k++; - } else { - delete img[i]; - } - } - - delete[] img; - img = img_tmp; - N_images = N_tmp; + assert(keep.size() == N_images); + + size_t N_tmp = 0; + for(std::vector::const_iterator it = keep.begin(); it != keep.end(); ++it) { + if(*it) { N_tmp++; } + } + + cv::Mat **img_tmp = new cv::Mat*[N_tmp]; + size_t i = 0; + size_t k = 0; + for(std::vector::const_iterator it = keep.begin(); it != keep.end(); ++it, ++i) { + if(*it) { + img_tmp[k] = img[i]; + k++; + } else { + delete img[i]; + } + } + + delete[] img; + img = img_tmp; + N_images = N_tmp; +} + +void TImgStack::crop(double x_min, double x_max, double y_min, double y_max) { + assert(x_min < x_max); + assert(y_min < y_max); + + uint32_t x0, x1, y0, y1; + + if(x_min <= rect->min[0]) { + x0 = 0; + } else { + x0 = (int)floor((x_min - rect->min[0]) / rect->dx[0]); + } + + if(x_max >= rect->max[0]) { + x1 = rect->N_bins[0]; + } else { + x1 = rect->N_bins[0] - (int)floor((rect->max[0] - x_max) / rect->dx[0]); + } + + if(y_min <= rect->min[1]) { + y0 = 0; + } else { + y0 = (int)floor((y_min - rect->min[1]) / rect->dx[1]); + } + + if(y_max >= rect->max[1]) { + y1 = rect->N_bins[1]; + } else { + y1 = rect->N_bins[1] - (int)floor((rect->max[1] - y_max) / rect->dx[1]); + } + + std::cerr << "Cropping images to (" << x0 << ", " << x1 << "), " + << "(" << y0 << ", " << y1 << ")" << std::endl; + + assert(x1 > x0); + assert(y1 > y0); + + cv::Rect crop_region(y0, x0, y1-y0, x1-x0); + + for(int i=0; imin[0] + x0 * rect->dx[0]; + double xmax_new = rect->min[0] + x1 * rect->dx[0]; + + double ymin_new = rect->min[1] + y0 * rect->dx[1]; + double ymax_new = rect->min[1] + y1 * rect->dx[1]; + + std::cerr << "New image limits: " + << "(" << xmin_new << ", " << xmax_new << ") " + << "(" << ymin_new << ", " << ymax_new << ")" + << std::endl; + + rect->min[0] = xmin_new; + rect->min[1] = ymin_new; + rect->max[0] = xmax_new; + rect->max[1] = ymax_new; + rect->N_bins[0] = x1 - x0; + rect->N_bins[1] = y1 - y0; } void TImgStack::set_rect(TRect& _rect) { - if(rect == NULL) { - rect = new TRect(_rect); - } else { - *rect = _rect; - } + if(rect != NULL) { + delete rect; + } + rect = new TRect(_rect); } void TImgStack::stack(cv::Mat& dest) { - if(N_images > 0) { - dest = *(img[0]); - for(size_t i=1; i 0) { + dest = *(img[0]); + for(size_t i=1; i N_images) { return false; } + if(rect == NULL) { return false; } + if(img[img_idx] == NULL) { + img[img_idx] = new cv::Mat; + } + *(img[img_idx]) = cv::Mat::zeros(rect->N_bins[0], rect->N_bins[1], CV_FLOATING_TYPE); + return true; +} + + +void TImgStack::smooth(std::vector sigma, double n_sigma) { + const int N_rows = rect->N_bins[0]; + const int N_cols = rect->N_bins[1]; + + assert(sigma.size() == N_rows); + assert(n_sigma > 0); + + // Source and destination rows for convolution + floating_t *src_img_row_up, *src_img_row_down, *dest_img_row; + int src_row_idx_up, src_row_idx_down; + + // Weight applied to each row + floating_t *dc = new floating_t[N_rows]; + floating_t a, c; + + // Number of times to shift image (= sigma * n_sigma) + int m_max; + + // Loop over images + for(int i=0; iclone()); + + // Loop over destination rows + for(int dest_row_idx=0; dest_row_idx N_rows) { m_max = N_rows; } + + // Determine weight to apply to each source pixel + a = -0.5 / (sigma[dest_row_idx]*sigma[dest_row_idx]); + c = 1.; + + for(int m=1; mrow(dest_row_idx) *= a; + + // Loop over row offsets (other than 0) + for(int m=1; m= N_rows) { src_row_idx_up = N_rows - 1; } + if(src_row_idx_down < 0) { src_row_idx_down = 0; } + + // Loop over images + if(img[i] != NULL) { + dest_img_row = img_s->ptr(dest_row_idx); + src_img_row_up = img[i]->ptr(src_row_idx_up); + src_img_row_down = img[i]->ptr(src_row_idx_down); + + // Loop over columns + for(int col=0; col read_img_stack( + const std::string& fname, + const std::string& dset +) { + // Open dataset + std::unique_ptr f = H5Utils::openFile(fname, H5Utils::READ); + if(!f) { return std::unique_ptr(nullptr); } + std::unique_ptr d = H5Utils::openDataSet(*f, dset); + if(!d) { return std::unique_ptr(nullptr); } + + // Read dimensions of image stack + size_t n_images; + double min[2], max[2]; + uint32_t n_pix[2]; + + std::cout << "Reading image metadata (nPix,min,max) ..." << std::endl; + H5::Attribute a_npix = d->openAttribute("nPix"); + H5::Attribute a_min = d->openAttribute("min"); + H5::Attribute a_max = d->openAttribute("max"); + + std::vector n_pix_vec = H5Utils::read_attribute_1d(a_npix); + std::vector min_vec = H5Utils::read_attribute_1d(a_min); + std::vector max_vec = H5Utils::read_attribute_1d(a_max); + + assert(n_pix_vec.size() == 2); + assert(min_vec.size() == 2); + assert(max_vec.size() == 2); + + std::copy(n_pix_vec.begin(), n_pix_vec.end(), &(n_pix[0])); + std::copy(min_vec.begin(), min_vec.end(), &(min[0])); + std::copy(max_vec.begin(), max_vec.end(), &(max[0])); + + H5::DataSpace dspace = d->getSpace(); + const hsize_t img_n_dims = dspace.getSimpleExtentNdims(); + assert(img_n_dims == 3); + hsize_t img_shape[3]; + dspace.getSimpleExtentDims(&(img_shape[0])); + n_images = img_shape[0]; + assert(img_shape[1] == n_pix[0]); + assert(img_shape[2] == n_pix[1]); + + // Initialize image stack + TRect rect(min, max, n_pix); + auto img_stack = std::unique_ptr(new TImgStack(n_images, rect)); + + for(size_t i=0; iinitialize_to_zero(i); + if(!res) { return std::unique_ptr(nullptr); } + } + + // Read in images + std::cout << "Reading image data ..." << std::endl; + float *buf = new float[n_pix[0] * n_pix[1] * n_images]; + d->read(buf, H5Utils::get_dtype()); + + for(size_t i=0; iimg[i]; + size_t i0 = i * n_pix[0]*n_pix[1]; + for(size_t j=0; jat(j,k) = buf[i0 + n_pix[1]*j + k]; + } + } + } + + delete[] buf; + + // Return image stack + return img_stack; } + +// void shift_image_vertical(cv::Mat& img, int n_pix) { +// +// } + + + +/**************************************************************************************************************************** + * + * TLOSTransform + * + ****************************************************************************************************************************/ + TLOSTransform::TLOSTransform(unsigned int ndim) - : TTransformParamSpace(ndim), _ndim(ndim) + : TTransformParamSpace(ndim), _ndim(ndim) {} TLOSTransform::~TLOSTransform() {} void TLOSTransform::transform(const double *const x, double *const y) { - y[0] = exp(x[0]); - for(unsigned int i=1; i<_ndim; i++) { - y[i] = y[i-1] + exp(x[i]); - } + y[0] = exp(x[0]); + for(unsigned int i=1; i<_ndim; i++) { + y[i] = y[i-1] + exp(x[i]); + } } TLOSCloudTransform::TLOSCloudTransform(unsigned int ndim) - : TTransformParamSpace(ndim), _ndim(ndim) + : TTransformParamSpace(ndim), _ndim(ndim) { - assert(!(ndim & 1)); - n_clouds = ndim / 2; + assert(!(ndim & 1)); + n_clouds = ndim / 2; } TLOSCloudTransform::~TLOSCloudTransform() {} void TLOSCloudTransform::transform(const double *const x, double *const y) { - y[0] = x[0]; - y[n_clouds] = exp(x[n_clouds]); - for(unsigned int i=1; i #include #include +#include #include +#include +#include +#include +#include #include #include #include +#include "definitions.h" + #include "model.h" #include "data.h" @@ -48,102 +55,328 @@ #include "chain.h" #include "binner.h" +#include "gaussian_process.h" +#include "neighbor_pixels.h" +#include "bridging_sampler.h" +#include "lru_cache.h" + // Parameters commonly passed to sampling routines struct TMCMCOptions { - unsigned int steps; - unsigned int samplers; - double p_replacement; - unsigned int N_runs; - - TMCMCOptions(unsigned int _steps, unsigned int _samplers, - double _p_replacement, unsigned int _N_runs) - : steps(_steps), samplers(_samplers), - p_replacement(_p_replacement), N_runs(_N_runs) - {} + unsigned int steps; + unsigned int samplers; + double p_replacement; + unsigned int N_runs; + + TMCMCOptions(unsigned int _steps, unsigned int _samplers, + double _p_replacement, unsigned int _N_runs) + : steps(_steps), samplers(_samplers), + p_replacement(_p_replacement), N_runs(_N_runs) + {} }; struct TImgStack { - cv::Mat **img; - TRect *rect; - - size_t N_images; - - TImgStack(size_t _N_images); - TImgStack(size_t _N_images, TRect &_rect); - ~TImgStack(); - - void cull(const std::vector &keep); - void resize(size_t _N_images); - void set_rect(TRect &_rect); - void stack(cv::Mat &dest); + cv::Mat **img; + TRect *rect; + + size_t N_images; + + TImgStack(size_t _N_images); + TImgStack(size_t _N_images, TRect &_rect); + ~TImgStack(); + + void cull(const std::vector& keep); + void crop(double x_min, double x_max, double y_min, double y_max); + + void resize(size_t _N_images); + void set_rect(TRect& _rect); + void stack(cv::Mat& dest); + + bool initialize_to_zero(unsigned int img_idx); + + void smooth(std::vector sigma, double n_sigma=5); + void normalize(double norm=1.0); }; + +std::unique_ptr read_img_stack( + const std::string& fname, + const std::string& group +); + + struct TLOSMCMCParams { - TImgStack *img_stack; - std::vector p0_over_Z, ln_p0_over_Z, inv_p0_over_Z; - double p0, lnp0; - - double *line_int; - float *Delta_EBV; - unsigned int N_runs; - unsigned int N_threads; - unsigned int N_regions; - - double EBV_max; - double EBV_guess_max; - std::vector EBV_prof_guess; - gsl_matrix *guess_cov, *guess_sqrt_cov; - - std::vector subpixel; - double subpixel_min, subpixel_max; - - double *Delta_EBV_prior; - double *log_Delta_EBV_prior; - double *sigma_log_Delta_EBV; - double alpha_skew; - - TLOSMCMCParams(TImgStack* _img_stack, const std::vector& _lnZ, double _p0, - unsigned int _N_runs, unsigned int _N_threads, unsigned int _N_regions, - double _EBV_max=-1.); - ~TLOSMCMCParams(); - - void set_p0(double _p0); - void set_subpixel_mask(TStellarData& data); - void set_subpixel_mask(std::vector& new_mask); - - void calc_Delta_EBV_prior(TGalacticLOSModel& gal_los_model, - double EBV_tot, int verbosity=1); - - void gen_guess_covariance(double scale_length); - - double* get_line_int(unsigned int thread_num); - float* get_Delta_EBV(unsigned int thread_num); - + TImgStack *img_stack; + std::vector p0_over_Z, ln_p0_over_Z, inv_p0_over_Z; + double p0, lnp0; + + double *line_int; + float *Delta_EBV; + unsigned int N_runs; + unsigned int N_threads; + unsigned int N_regions; + + double EBV_max; + double EBV_guess_max; + std::vector EBV_prof_guess; + gsl_matrix *guess_cov, *guess_sqrt_cov; + + std::vector subpixel; + double subpixel_min, subpixel_max; + + double *Delta_EBV_prior; + double *log_Delta_EBV_prior; + double *sigma_log_Delta_EBV; + double alpha_skew; + + TLOSMCMCParams(TImgStack* _img_stack, const std::vector& _lnZ, + double _p0, unsigned int _N_runs, unsigned int _N_threads, + unsigned int _N_regions, double _EBV_max=-1.); + ~TLOSMCMCParams(); + + void set_p0(double _p0); + void set_subpixel_mask(TStellarData& data); + void set_subpixel_mask(std::vector& new_mask); + + void calc_Delta_EBV_prior(TGalacticLOSModel& gal_los_model, + double log_Delta_EBV_floor, + double log_Delta_EBV_ceil, + double sigma, double EBV_tot, + int verbosity=1); + + void gen_guess_covariance(double scale_length); + + double* get_line_int(unsigned int thread_num); + float* get_Delta_EBV(unsigned int thread_num); + +}; + + +struct TDiscreteLosMcmcParams { + // Information on neighboring pixels from previous iterations + std::unique_ptr neighbor_pixels; + //std::vector neighbor_sample; // Which sample to choose for each neighbor + std::vector log_p_sample; // Workspace for storing log sample probabilities + std::vector p_sample; // Workspace for storing sample probabilities + //std::vector gibbs_order; // Workspace for storing order of Gibbs sampling + + std::unique_ptr img_stack; // Stack of (distance, reddening) posteriors for stars + double y_zero_idx; // y-index corresponding to zero reddening + + double* line_int; // Line integral through line of sight for each thread + int16_t* E_pix_idx; // LOS reddening profile, in the form of the pixel y-index at each distance (for each thread) + + unsigned int n_dists, n_E; // # of distance and reddening pixels, respectively + unsigned int N_runs; // # of times to repeat inference (to check convergence) + unsigned int N_threads; // # of threads (can be less than # of runs) + + // Random number generator + std::mt19937 r; + + // Priors on Delta E in each distance bin + double mu_log_dE, sigma_log_dE; + double mu_log_dy, inv_sigma_log_dy; + double inv_sigma_dy_neg; + + std::vector mu_log_dE_0, sigma_log_dE_0; + + // Distance-dependent priors on Delta E + std::shared_ptr log_P_dy; + unsigned int priors_subsampling; + + // Constructor/destructor + TDiscreteLosMcmcParams(std::unique_ptr _img_stack, + std::unique_ptr _neighbor_pixels, + unsigned int _N_runs, + unsigned int _N_threads, + int verbosity=0); + ~TDiscreteLosMcmcParams(); + + // Access fit information for one thread + double* get_line_int(unsigned int thread_num); + int16_t* get_E_pix_idx(unsigned int thread_num); + + // Line-of-sight integrals + void los_integral_discrete(const int16_t *const y_idx, + double *const line_int_ret); + + // Prior on line-of-sight dust distribution + floating_t log_dy_prior( + const int16_t x_idx, + const int16_t dy); // Indiv. dist. + floating_t log_prior(const int16_t *const y_idx); // Entire profile + + floating_t log_dy_prior( + const int16_t x_idx, + const int16_t dy, + const cv::Mat& lnP_dy); // Indiv. dist. + floating_t log_prior( + const int16_t *const y_idx, + const cv::Mat& lnP_dy); // Entire profile + + // Step proposal + void los_integral_diff_step( + const int16_t x_idx, + const int16_t y_idx_old, + const int16_t y_idx_new, + double *const delta_line_int_ret); + + floating_t log_prior_diff_step( + const int16_t x_idx, + const int16_t *const y_idx_los_old, + const int16_t y_idx_new); + floating_t log_prior_diff_step( + const int16_t x_idx, + const int16_t *const y_idx_los_old, + const int16_t y_idx_new, + const cv::Mat& lnP_dy); + + // Swap proposal + void los_integral_diff_swap( + const int16_t x0_idx, + const int16_t *const y_idx, + double *const delta_line_int_ret); + + floating_t log_prior_diff_swap( + const int16_t x0_idx, + const int16_t *const y_idx_los_old, + const cv::Mat& lnP_dy); + floating_t log_prior_diff_swap( + const int16_t x0_idx, + const int16_t *const y_idx_los_old); + + // Shift-right proposal + bool shift_r_step_valid( + const int16_t x_idx, + const int16_t dy, + const int16_t *const y_idx_old); + + void los_integral_diff_shift_r( + const int16_t x_idx, + const int16_t dy, + const int16_t *const y_idx_old, + double *const delta_line_int_ret); + + floating_t log_prior_diff_shift_r( + const int16_t x_idx, + const int16_t dy, + const int16_t *const y_idx_los_old, + const cv::Mat& lnP_dy); + floating_t log_prior_diff_shift_r( + const int16_t x_idx, + const int16_t dy, + const int16_t *const y_idx_los_old); + + // Shift-left proposal + bool shift_l_step_valid( + const int16_t x_idx, + const int16_t dy, + const int16_t *const y_idx_old); + + void los_integral_diff_shift_l( + const int16_t x_idx, + const int16_t dy, + const int16_t *const y_idx_old, + double *const delta_line_int_ret); + + floating_t log_prior_diff_shift_l( + const int16_t x_idx, + const int16_t dy, + const int16_t *const y_idx_los_old, + const cv::Mat& lnP_dy); + floating_t log_prior_diff_shift_l( + const int16_t x_idx, + const int16_t dy, + const int16_t *const y_idx_los_old); + + // Miscellaneous functions + void los_integral_diff_shift_compare_operations( + const int16_t x_idx, + const int16_t dy, + const int16_t *const y_idx_old, + unsigned int& n_eval_diff, + unsigned int& n_eval_cumulative); + + void guess_EBV_profile_discrete(int16_t *const y_idx_ret, gsl_rng *r); + + void set_sigma_log_dE(const double s); + + void initialize_priors( + TGalacticLOSModel& gal_los_model, + double log_Delta_EBV_floor, + double log_Delta_EBV_ceil, + double sigma_log_Delta_EBV, + int verbosity=0); + + void update_priors_image( + std::vector& neighbor_sample, + double alpha_skew, + int subsampling=10, + const double shift_weight=-1., + int verbosity=0); + + void update_priors_image( + cv::Mat& img, + std::vector& neighbor_sample, + double alpha_skew, + int subsampling=10, + const double shift_weight=-1., + int verbosity=0); + + void set_central_delta(int16_t* y_idx); }; + +// Sample neighboring pixels +double neighbor_gibbs_step( + int pix, + TNeighborPixels& neighbor_pixels, + std::vector& neighbor_sample, + std::vector& log_p_sample_ws, + std::vector& p_sample_ws, + std::mt19937& r, + double beta=1.); + + +double neighbor_gibbs_step_shifted( + const int pix, + TNeighborPixels& neighbor_pixels, + std::vector& neighbor_sample, + std::vector& log_p_sample_ws, + std::vector& p_sample_ws, + std::mt19937& r, + const double beta, + const double shift_weight); + + +void randomize_neighbors( + TNeighborPixels& neighbor_pixels, + std::vector& neighbor_sample, + std::mt19937& r); + + // Transform from log(DeltaEBV) to cumulative EBV for piecewise-linear l.o.s. fit class TLOSTransform : public TTransformParamSpace { private: - size_t _ndim; + size_t _ndim; public: - TLOSTransform(unsigned int ndim); - virtual ~TLOSTransform(); - - virtual void transform(const double *const x, double *const y); + TLOSTransform(unsigned int ndim); + virtual ~TLOSTransform(); + + virtual void transform(const double *const x, double *const y); }; // Transform to cumulative EBV for cloud l.o.s. fit class TLOSCloudTransform : public TTransformParamSpace { private: - size_t _ndim; - size_t n_clouds; - + size_t _ndim; + size_t n_clouds; + public: - TLOSCloudTransform(unsigned int ndim); - virtual ~TLOSCloudTransform(); - - virtual void transform(const double *const x, double *const y); + TLOSCloudTransform(unsigned int ndim); + virtual ~TLOSCloudTransform(); + + virtual void transform(const double *const x, double *const y); }; // Testing functions @@ -151,13 +384,21 @@ void test_extinction_profiles(TLOSMCMCParams ¶ms); // Sample piecewise-linear model -void sample_los_extinction(const std::string& out_fname, const std::string& group_name, - TMCMCOptions &options, TLOSMCMCParams ¶ms, - int verbosity=1); +void sample_los_extinction( + const std::string& out_fname, const std::string& group_name, + TMCMCOptions &options, TLOSMCMCParams ¶ms, + int verbosity=1); -double lnp_los_extinction(const double *const Delta_EBV, unsigned int N_regions, TLOSMCMCParams ¶ms); +double lnp_los_extinction( + const double *const Delta_EBV, + unsigned int N_regions, + TLOSMCMCParams ¶ms); -void gen_rand_los_extinction_from_guess(double *const logEBV, unsigned int N, gsl_rng *r, TLOSMCMCParams ¶ms); +void gen_rand_los_extinction_from_guess( + double *const logEBV, + unsigned int N, + gsl_rng *r, + TLOSMCMCParams ¶ms); void gen_rand_los_extinction(double *const Delta_EBV, unsigned int N, gsl_rng *r, TLOSMCMCParams ¶ms); @@ -192,5 +433,63 @@ void los_integral_clouds(TImgStack &img_stack, const double *const subpixel, dou const double *const logDelta_EBV, unsigned int N_clouds); +// Sampling parameters for discrete l.o.s. model +struct TDiscreteLOSSamplingSettings { + unsigned int n_temperatures = 5; + // Spacing of sampling temperatures: + // 0 < beta_spacing < 1 + // 1 -> degenerate + // 0 -> maximal spacing + double beta_spacing = 0.85; + // # of steps to take in central pixel per update + unsigned int central_steps_per_update = 20; // times # of distances + // # of neighbor steps to take per update + unsigned int neighbor_steps_per_update = 5; // times # of neighbors + // # of update cycles per swap + unsigned int updates_per_swap = 1; + // # of swaps to attempt + unsigned int n_swaps = 1000; + // Fraction of sampling to use as burn-in + double burnin_frac = 1./4.; + // # of samples to save + unsigned int n_save = 100; + // Deformation of prior to correlate neighboring distances + double log_shift_weight_min = -3.; // At temperature = 1 + double log_shift_weight_max = -1.; // At highest temperature + bool shift_weight_ladder_logarithmic = false; + // If true, save all temperature chains + bool save_all_temperatures = false; + // Outlier fraction + double p_badstar = 1.e-5; // Higher means less weight for outliers +}; + + +// Sample discrete line-of-sight model +void sample_los_extinction_discrete( + const std::string& out_fname, + const std::string& group_name, + TMCMCOptions &options, + TDiscreteLosMcmcParams ¶ms, + const std::vector& neighbor_sample, + const TDiscreteLOSSamplingSettings& s, + int verbosity); + + +// Sample combinations of neighboring pixels using parallel tempering +void sample_neighbors_pt( + TNeighborPixels& neighbors, + std::vector& chain, + int verbosity); + + +// Sample combinations of neighboring pixels using the bridging sampler +void sample_neighbors( + TNeighborPixels& neighbors, + std::vector& chain, + int verbosity); + + +void seed_prng(std::mt19937& r); + #endif // _LOS_SAMPLER_H__ diff --git a/src/lru_cache.h b/src/lru_cache.h new file mode 100644 index 0000000..e945b6a --- /dev/null +++ b/src/lru_cache.h @@ -0,0 +1,340 @@ +/* + * lru_cache.h + * + * Header-only implementation of a least-recently-used cache in C++. + * Requires C++14 or above. + * + * MIT License + * + * Copyright (c) 2018 Gregory Maurice Green + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + + +#ifndef _LRU_CACHE_H__ +#define _LRU_CACHE_H__ + + +#include +#include +#include +#include +#include + + +#define LRUCACHE_VERBOSE 1 // Set to 1 for hit/miss stats, 0 for quiet + +#if LRUCACHE_VERBOSE +#include +#endif + + +namespace LRUCache { + + +template +class VectorHasher { + // Hashing function for vectors, required to use them as + // keys in an unordered_map. Adapted from HolKann's + // StackOverflow answer: . +public: + std::size_t operator()(const std::vector& vec) const; +}; + + +template +std::size_t VectorHasher::operator()( + const std::vector& vec) const +{ + std::size_t seed = vec.size(); + for(auto& v : vec) { + seed ^= std::hash{}(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2); + } + return seed; +} + + + +template> +class LRUCache { +public: + LRUCache(uint32_t capacity, const TValue& empty_value); + ~LRUCache(); + + TValue get(const TKey& key); + void set(const TKey& key, const TValue& value); + +protected: + uint32_t capacity; // Max # of items to store. + TValue empty_value; // Value to return when item not in cache + + // Order in which keys have been accessed. Most recent first. + std::list access_order; + + // Map to store (key, value) pairs. + std::unordered_map cache; + + // Map for quick lookup of access order. + std::unordered_map::iterator, THash> access_order_it; + + typename std::unordered_map::iterator push_front(const TKey& key, const TValue& value); + void bring_to_front(const TKey& key); + void remove_lru(); + + #if LRUCACHE_VERBOSE + uint64_t n_hit, n_miss, n_replace; + #endif +}; + + +template> +class CachedFunction : public LRUCache { +public: + CachedFunction(std::function f, uint32_t capacity); + CachedFunction(std::function f, uint32_t capacity, const TValue& empty_value); + ~CachedFunction(); + + TValue eval(const TKey& arg); + TValue operator()(const TKey& arg); + + void eval(const TKey& arg, std::function); + void operator()(const TKey& arg, std::function); + + TValue& eval_ref(const TKey& arg); + +private: + std::function f; +}; + + +template +CachedFunction::CachedFunction(std::function f, uint32_t capacity) + : LRUCache(capacity, TValue()), f(f) +{} + + +template +CachedFunction::CachedFunction(std::function f, uint32_t capacity, const TValue& empty_value) + : LRUCache(capacity, empty_value), f(f) +{} + + +template +CachedFunction::~CachedFunction() {} + + +template +TValue CachedFunction::eval(const TKey& arg) { + // Look up key in cache + auto cache_it = this->cache.find(arg); + if(cache_it == this->cache.end()) { // Key not found + TValue value = f(arg); + this->push_front(arg, value); + return value; + } else { // Key found + #if LRUCACHE_VERBOSE + this->n_hit++; + #endif + + // Update access order + this->bring_to_front(arg); + // Return cached value + return cache_it->second; + } +} + + +template +void CachedFunction::eval(const TKey& arg, std::function g) { + // Look up key in cache + auto cache_it = this->cache.find(arg); + if(cache_it == this->cache.end()) { // Key not found + TValue value = f(arg); + this->push_front(arg, value); + // Operate on newly computed value + g(value); + } else { // Key found + #if LRUCACHE_VERBOSE + this->n_hit++; + #endif + + // Update access order + this->bring_to_front(arg); + // Operate on cached value + g(cache_it->second); + } +} + + +template +TValue& CachedFunction::eval_ref(const TKey& arg) { + // Look up key in cache + auto cache_it = this->cache.find(arg); + if(cache_it == this->cache.end()) { // Key not found + TValue value = f(arg); + auto it = this->push_front(arg, value); + return it->second; + } else { // Key found + #if LRUCACHE_VERBOSE + this->n_hit++; + #endif + + // Update access order + this->bring_to_front(arg); + // Return cached value + return cache_it->second; + } +} + + +template +TValue CachedFunction::operator()(const TKey& arg) { + return eval(arg); +} + + +template +void CachedFunction::operator()(const TKey& arg, std::function g) { + return eval(arg, g); +} + + +template +LRUCache::LRUCache(uint32_t capacity, const TValue& empty_value) + : capacity(capacity), empty_value(empty_value) +{ + #if LRUCACHE_VERBOSE + n_hit = 0; + n_miss = 0; + n_replace = 0; + #endif +} + + +template +LRUCache::~LRUCache() { + #if LRUCACHE_VERBOSE + std::cout << "LRUCache hits/misses/replacements = " + << n_hit << " / " + << n_miss << " / " + << n_replace << std::endl; + #endif +} + + +template +TValue LRUCache::get(const TKey& key) { + // Look up key in cache + auto cache_it = cache.find(key); + if(cache_it == cache.end()) { // Key not found + #if LRUCACHE_VERBOSE + n_miss++; + #endif + + return empty_value; + } else { // Key found + #if LRUCACHE_VERBOSE + n_hit++; + #endif + + // Update access order + bring_to_front(key); + // Return cached value + return cache_it->second; + } +} + + +template +typename std::unordered_map::iterator LRUCache::push_front( + const TKey& key, + const TValue& value) +{ + #if LRUCACHE_VERBOSE + n_miss++; + #endif + + // Add (key, value) pair to cache + auto cache_it = cache.insert(std::make_pair(key, value)).first; + // Insert key into access-order list + access_order.push_front(key); + // Update access-order lookup + access_order_it.insert(std::make_pair(key, access_order.begin())); + // If over capacity, remove least-recently-used key + if(cache.size() > capacity) { + remove_lru(); + } + + return cache_it; +} + +template +void LRUCache::set(const TKey& key, const TValue& value) { + // Look up key in cache + auto cache_it = cache.find(key); + if(cache_it == cache.end()) { // Key not in cache + push_front(key, value); + } else { // Key found + #if LRUCACHE_VERBOSE + n_hit++; + #endif + + // Bring key to front of access order list + bring_to_front(key); + // Update value + cache_it->second = value; + } +} + + +template +void LRUCache::remove_lru() { + #if LRUCACHE_VERBOSE + n_replace++; + #endif + + // Look up key of least-recently-used element + const TKey& key = access_order.back(); + // Erase key from cache and access-order-iterator lookup + cache.erase(key); + access_order_it.erase(key); + // Erase key from access-order list + access_order.pop_back(); +} + + +template +void LRUCache::bring_to_front(const TKey& key) { + auto ao_it = access_order_it.find(key); // Assumed to be found + if(ao_it->second != access_order.begin()) { + // Move key to front of access-order list + access_order.erase(ao_it->second); + access_order.push_front(key); + // Update location of key in access-order-iterator lookup + ao_it->second = access_order.begin(); + } +} + + +} // namespace LRUCache + + +#endif // _LRU_CACHE_H__ diff --git a/src/main.cpp b/src/main.cpp index addf32c..6428304 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,24 +1,24 @@ /* * main.cpp - * + * * This file is part of bayestar. * Copyright 2012 Gregory Green - * + * * Bayestar is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. - * + * */ @@ -26,605 +26,893 @@ #include #include -#include - #include "cpp_utils.h" #include "model.h" #include "data.h" #include "sampler.h" #include "los_sampler.h" +#include "star_exact.h" +#include "neighbor_pixels.h" #include "bayestar_config.h" +#include "program_opts.h" using namespace std; -struct TProgramOpts { - string input_fname; - string output_fname; - - bool save_surfs; - - double err_floor; - - bool synthetic; - unsigned int star_steps; - unsigned int star_samplers; - double star_p_replacement; - double min_EBV; - bool star_priors; - - double sigma_RV; - double mean_RV; - - unsigned int N_regions; - unsigned int los_steps; - unsigned int los_samplers; - double los_p_replacement; - - unsigned int N_clouds; - unsigned int cloud_steps; - unsigned int cloud_samplers; - double cloud_p_replacement; - - bool disk_prior; - bool SFD_prior; - bool SFD_subpixel; - double ev_cut; - - unsigned int N_runs; - unsigned int N_threads; - - bool clobber; - - bool test_mode; - - int verbosity; - - string LF_fname; - string template_fname; - string ext_model_fname; - - TGalStructParams gal_struct_params; - - TProgramOpts() { - input_fname = "NONE"; - output_fname = "NONE"; - - save_surfs = false; - - err_floor = 20; - - synthetic = false; - star_steps = 1000; - star_samplers = 5; - star_p_replacement = 0.2; - min_EBV = 0.; - star_priors = true; - - sigma_RV = -1.; - mean_RV = 3.1; - - N_regions = 30; - los_steps = 4000; - los_samplers = 2; - los_p_replacement = 0.0; - - N_clouds = 1; - cloud_steps = 2000; - cloud_samplers = 80; - cloud_p_replacement = 0.2; - - disk_prior = false; - SFD_prior = false; - SFD_subpixel = false; - ev_cut = 10.; - - N_runs = 4; - N_threads = 1; - - clobber = false; - - test_mode = false; - - verbosity = 0; - - LF_fname = DATADIR "PSMrLF.dat"; - template_fname = DATADIR "PScolors.dat"; - ext_model_fname = DATADIR "PSExtinction.dat"; - } -}; - - -template -string to_string(const T& x) { - stringstream ss; - ss << x; - return ss.str(); +int full_workflow(TProgramOpts &opts, int argc, char **argv) { + /* + * Determines stellar posterior densities, + * then determines the l.o.s. reddening. + */ + + + /* + * MCMC Options + */ + + TMCMCOptions star_options(opts.star_steps, opts.star_samplers, opts.star_p_replacement, opts.N_runs); + TMCMCOptions cloud_options(opts.cloud_steps, opts.cloud_samplers, opts.cloud_p_replacement, opts.N_runs); + TMCMCOptions los_options(opts.los_steps, opts.los_samplers, opts.los_p_replacement, opts.N_runs); + + TMCMCOptions discrete_los_options(opts.discrete_steps, 1, 0., opts.N_runs); // TODO: Create commandline options for this + + + /* + * Construct models + */ + + TStellarModel *emplib = NULL; + TSyntheticStellarModel *synthlib = NULL; + if(opts.synthetic) { + synthlib = new TSyntheticStellarModel(DATADIR "PS1templates.h5"); + } else { + emplib = new TStellarModel(opts.LF_fname, opts.template_fname); + } + TExtinctionModel ext_model(opts.ext_model_fname); + + TEBVSmoothing EBV_smoothing(opts.smoothing_alpha_coeff, + opts.smoothing_beta_coeff, + opts.pct_smoothing_min, + opts.pct_smoothing_max); + + /* + * Execute + */ + + omp_set_num_threads(opts.N_threads); + + // Get list of pixels in input file + vector pix_name; + get_input_pixels(opts.input_fname, pix_name); + cout << "# " << pix_name.size() << " pixels in input file." << endl << endl; + + // Remove the output file + if(opts.clobber) { + remove(opts.output_fname.c_str()); + } + + H5::Exception::dontPrint(); + + // Run each pixel + timespec t_start, t_mid, t_end; + + double t_tot, t_star; + unsigned int pixel_list_no = 0; + + for(vector::iterator it = pix_name.begin(); it != pix_name.end(); ++it, pixel_list_no++) { + clock_gettime(CLOCK_MONOTONIC, &t_start); + + cout << "# Pixel: " << *it + << " (" << pixel_list_no + 1 << " of " << pix_name.size() << ")" + << endl; + + // Load input photometry + TStellarData stellar_data(opts.input_fname, *it, opts.err_floor); + TGalacticLOSModel los_model( + stellar_data.l, + stellar_data.b, + opts.gal_struct_params + ); + + cout << "# HEALPix index: " << stellar_data.healpix_index + << " (nside = " << stellar_data.nside << ")" << endl; + cout << "# (l, b) = " + << stellar_data.l << ", " << stellar_data.b << endl; + if(opts.SFD_prior) { + cout << "# E(B-V)_SFD = " << stellar_data.EBV << endl; + } + cout << "# " << stellar_data.star.size() << " stars in pixel" << endl; + + + // Check if this pixel has already been fully processed + if(!(opts.clobber)) { + bool process_pixel = false; + + std::unique_ptr out_file = H5Utils::openFile( + opts.output_fname, + H5Utils::READ | H5Utils::WRITE | H5Utils::DONOTCREATE + ); + + if(!out_file) { + process_pixel = true; + + //cout << "File does not exist" << endl; + } else { + //cout << "File exists" << endl; + //stringstream group_name; + //group_name << stellar_data.healpix_index; + //group_name << stellar_data.nside << "-" << stellar_data.healpix_index; + + std::unique_ptr pix_group = H5Utils::openGroup( + *out_file, + *it, + H5Utils::READ | H5Utils::WRITE | H5Utils::DONOTCREATE + ); + + if(!pix_group) { + process_pixel = true; + } else { + //cout << "Group exists" << endl; + + if(opts.force_pix.size() != 0) { + std::stringstream pix_spec_ss; + pix_spec_ss << stellar_data.nside + << "-" << stellar_data.healpix_index; + std::string pix_spec_str = pix_spec_ss.str(); + for(auto const &s : opts.force_pix) { + if(pix_spec_str == s) { + std::cerr << "Force-reprocessing pixel " << s << std::endl; + process_pixel = true; + break; + } + } + } + + if(opts.sample_stars) { + if(!H5Utils::dataset_exists("stellar chains", *pix_group)) { + process_pixel = true; + } + } + if(opts.save_surfs) { + if(!H5Utils::dataset_exists("stellar pdfs", *pix_group)) { + process_pixel = true; + } + } + + if((!process_pixel) && (opts.N_clouds != 0)) { + if(!H5Utils::dataset_exists("clouds", *pix_group)) { + process_pixel = true; + } + } + + if((!process_pixel) && (opts.N_regions != 0)) { + if(!H5Utils::dataset_exists("los", *pix_group)) { + process_pixel = true; + } + } + + if((!process_pixel) && (opts.discrete_los)) { + if(!H5Utils::dataset_exists("discrete-los", *pix_group)) { + process_pixel = true; + } + } + + // If pixel is missing data, remove it, so that it can be regenerated + if(process_pixel) { + try { + out_file->unlink(*it); + } catch(H5::FileIException unlink_err) { + cout << "Unable to remove group: '" << *it << "'" + << endl; + } + } + } + } + + if(!process_pixel) { + cout << "# Pixel is already present in output. Skipping." + << endl << endl; + + continue; // All information is already present in output file + } + } + + // Prepare data structures for stellar parameters + unsigned int n_stars = stellar_data.star.size(); + std::unique_ptr img_stack(new TImgStack(n_stars)); + vector conv; + vector lnZ; + vector chi2; + + bool gatherSurfs = (opts.N_regions || opts.N_clouds || opts.save_surfs); + + // Sample individual stars + if(!opts.sample_stars) { + // Grid evaluation of stellar models + grid_eval_stars(los_model, ext_model, *emplib, + stellar_data, EBV_smoothing, + *img_stack, chi2, + opts.save_surfs, + opts.save_gridstars, + opts.output_fname, + opts.star_priors, + opts.use_gaia, + opts.mean_RV, opts.verbosity); + } else if(opts.synthetic) { + // MCMC sampling of synthetic stellar model + sample_indiv_synth(opts.output_fname, star_options, los_model, *synthlib, ext_model, + stellar_data, *img_stack, conv, lnZ, opts.sigma_RV, + opts.min_EBV, opts.save_surfs, gatherSurfs, opts.verbosity); + } else { + #ifdef _USE_PARALLEL_TEMPERING__ + // MCMC sampling of empirical stellar model + sample_indiv_emp_pt(opts.output_fname, star_options, los_model, + *emplib, ext_model, EBV_smoothing, + stellar_data, *img_stack, conv, lnZ, + opts.mean_RV, opts.sigma_RV, opts.min_EBV, + opts.save_surfs, gatherSurfs, opts.star_priors, + opts.verbosity); + #else // _USE_PARALLEL_TEMPERING + // MCMC sampling of empirical stellar model + sample_indiv_emp(opts.output_fname, star_options, los_model, + *emplib, ext_model, EBV_smoothing, + stellar_data, *img_stack, conv, lnZ, + opts.mean_RV, opts.sigma_RV, opts.min_EBV, + opts.save_surfs, gatherSurfs, opts.star_priors, + opts.verbosity); + #endif // _USE_PARALLEL_TERMPERING + } + + clock_gettime(CLOCK_MONOTONIC, &t_mid); + + // Tag output pixel with HEALPix nside and index + stringstream group_name; + group_name << "/" << *it; + + try { + H5Utils::add_watermark(opts.output_fname, group_name.str(), "nside", stellar_data.nside); + H5Utils::add_watermark(opts.output_fname, group_name.str(), "healpix_index", stellar_data.healpix_index); + H5Utils::add_watermark(opts.output_fname, group_name.str(), "l", stellar_data.l); + H5Utils::add_watermark(opts.output_fname, group_name.str(), "b", stellar_data.b); + H5Utils::add_watermark(opts.output_fname, group_name.str(), "n_stars", stellar_data.star.size()); + } catch(H5::AttributeIException err_att_exists) { } + + // Filter based on goodness-of-fit and convergence + vector keep; + bool filter_tmp; + size_t n_filtered = 0; + + std::vector subpixel; + vector lnZ_filtered; + + if(opts.sample_stars) { + // For sampled stars, use convergence and lnZ + assert(conv.size() == lnZ.size()); + for(vector::iterator it_lnZ = lnZ.begin(); it_lnZ != lnZ.end(); ++it_lnZ) { + if(!std::isnan(*it_lnZ) && !is_inf_replacement(*it_lnZ)) { + lnZ_filtered.push_back(*it_lnZ); + } + } + double lnZmax = percentile_const(lnZ_filtered, 95.0); + if(opts.verbosity >= 2) { + cout << "# ln(Z)_95pct = " << lnZmax << endl; + } + + lnZ_filtered.clear(); + for(size_t n=0; n lnZmax - (25. + opts.ev_cut)) + && !std::isnan(lnZ[n]) + && !is_inf_replacement(lnZ[n]) + && (stellar_data.star[n].EBV < opts.subpixel_max); + keep.push_back(filter_tmp); + if(filter_tmp) { + subpixel.push_back(stellar_data.star[n].EBV); + lnZ_filtered.push_back(lnZ[n] - lnZmax); + } else { + n_filtered++; + } + } + } else { + // For grid-evaluated stars, use chi^2 / passband + for(size_t n=0; n(opts.output_fname, group_name.str(), "n_stars_rejected", n_filtered); + } catch(H5::AttributeIException err_att_exists) { } + // Save rejection fraction + double reject_frac = (double)n_filtered / chi2.size(); + try { + H5Utils::add_watermark(opts.output_fname, group_name.str(), "reject_frac", reject_frac); + } catch(H5::AttributeIException err_att_exists) { } + } + if(gatherSurfs) { img_stack->cull(keep); } + + cout << "# of stars filtered: " + << n_filtered << " of " << n_stars; + cout << " (" << 100. * (double)n_filtered / n_stars + << " %)" << endl; + + // Fit line-of-sight extinction profile + if((opts.N_clouds != 0) || (opts.N_regions != 0) || opts.discrete_los) { + if(n_filtered >= n_stars) { + cout << "Every star was rejected!" << endl; + } else { + double p0 = exp(-5. - opts.ev_cut); + double EBV_max = -1.; + if(opts.SFD_prior) { + if(opts.SFD_subpixel) { + EBV_max = 1.; + } else { + EBV_max = stellar_data.EBV; + } + } + + TLOSMCMCParams params( + img_stack.get(), lnZ_filtered, p0, + opts.N_runs, opts.N_threads, + opts.N_regions, EBV_max + ); + if(opts.SFD_subpixel) { params.set_subpixel_mask(subpixel); } + + if(opts.test_mode) { + test_extinction_profiles(params); + } + + // Sample discrete l.o.s. model + if(opts.discrete_los) { + std::unique_ptr neighbor_pixels; + + if((opts.neighbor_lookup_fname != "NONE") && + (opts.pixel_lookup_fname != "NONE") && + (opts.output_fname_pattern != "NONE")) + { + // Load information on neighboring pixels + cout << "Loading information on neighboring pixels ..." << endl; + neighbor_pixels = std::make_unique( + stellar_data.nside, + stellar_data.healpix_index, + opts.neighbor_lookup_fname, + opts.pixel_lookup_fname, + opts.output_fname_pattern, + 1000); + + if(!neighbor_pixels->data_loaded()) { + cerr << "Failed to load neighboring pixels! Aborting." + << endl; + return 1; + } + + // Calculate covariance matrices tying + // pixels together at each distance + neighbor_pixels->init_covariance( + opts.correlation_scale, + opts.d_soft, + opts.gamma_soft); + } + + TDiscreteLosMcmcParams discrete_los_params( + std::move(img_stack), + std::move(neighbor_pixels), + 1, 1, + opts.verbosity); + discrete_los_params.initialize_priors( + los_model, + opts.log_Delta_EBV_floor, + opts.log_Delta_EBV_ceil, + opts.sigma_log_Delta_EBV, + opts.verbosity + ); + + std::vector neighbor_sample; + + if(discrete_los_params.neighbor_pixels) { + cout << "Initializing dominant distances ..." << endl; + discrete_los_params.neighbor_pixels->init_dominant_dist(opts.verbosity); + + //cout << "Resampling neighboring pixels ..." << endl; + //sample_neighbors(*(discrete_los_params.neighbor_pixels), opts.verbosity); + //sample_neighbors_pt( + // *(discrete_los_params.neighbor_pixels), + // neighbor_sample, + // opts.verbosity + //); + } + + cout << "Sampling line of sight discretely ..." << endl; + sample_los_extinction_discrete( + opts.output_fname, + *it, + discrete_los_options, + discrete_los_params, + neighbor_sample, + opts.dsc_samp_settings, + opts.verbosity + ); + cout << "Done with discrete sampling." << endl; + } + + if(opts.N_clouds != 0) { + sample_los_extinction_clouds( + opts.output_fname, *it, + cloud_options, params, + opts.N_clouds, opts.verbosity + ); + } + if(opts.N_regions != 0) { + // Covariance matrix for guess has (anti-)correlation + // length of 1 distance bin + params.gen_guess_covariance(1.); + + if(opts.disk_prior) { + params.alpha_skew = 1.; + params.calc_Delta_EBV_prior( + los_model, + opts.log_Delta_EBV_floor, + opts.log_Delta_EBV_ceil, + stellar_data.EBV, + 1.4, + opts.verbosity + ); + } + + sample_los_extinction( + opts.output_fname, *it, + los_options, params, opts.verbosity + ); + } + } + } + + clock_gettime(CLOCK_MONOTONIC, &t_end); + t_tot = (t_end.tv_sec - t_start.tv_sec) + + 1.e-9 * (t_end.tv_nsec - t_start.tv_nsec); + t_star = (t_mid.tv_sec - t_start.tv_sec) + + 1.e-9 * (t_mid.tv_nsec - t_start.tv_nsec); + + try { + H5Utils::add_watermark(opts.output_fname, group_name.str(), "t_tot", (float)t_tot); + H5Utils::add_watermark(opts.output_fname, group_name.str(), "t_star", (float)t_star); + } catch(H5::AttributeIException err_att_exists) { } + + if(opts.verbosity >= 1) { + cout << endl + << "===================================================" + << endl; + } + cout << "# Time elapsed for pixel: " + << setprecision(2) << t_tot + << " s (" << setprecision(2) + << t_tot / (double)(stellar_data.star.size()) + << " s / star)" << endl; + cout << "# Percentage of time spent on l.o.s. fit: " + << setprecision(2) << 100. * (t_tot - t_star) / t_tot + << " %" << endl; + if(opts.verbosity >= 1) { + cout << "===================================================" + << endl; + } + cout << endl; + } + + + /* + * Add additional metadata to output file + */ + try { + string watermark = GIT_BUILD_VERSION; + H5Utils::add_watermark( + opts.output_fname, "/", + "bayestar git commit", + watermark + ); + } catch(H5::AttributeIException err_att_exists) { } + + stringstream commandline_args; + for(int i=0; i( + opts.output_fname, "/", + "commandline invocation", + commandline_args_str + ); + } catch(H5::AttributeIException err_att_exists) { } + + + /* + * Cleanup + */ + + if(synthlib != NULL) { delete synthlib; } + if(emplib != NULL) { delete emplib; } + + return 0; } -int get_program_opts(int argc, char **argv, TProgramOpts &opts) { - namespace po = boost::program_options; - - std::string config_fname = "NONE"; - - po::options_description config_desc("Configuration-file options"); - config_desc.add_options() - ("err-floor", po::value(&(opts.err_floor)), ("Error to add in quadrature (in millimags) (default: " + to_string(opts.err_floor) + ")").c_str()) - ("synthetic", "Use synthetic photometric library (default: use empirical library)") - ("star-steps", po::value(&(opts.star_steps)), ("# of MCMC steps per star (per sampler) (default: " + to_string(opts.star_steps) + ")").c_str()) - ("star-samplers", po::value(&(opts.star_samplers)), ("# of samplers per dimension (stellar fit) (default: " + to_string(opts.star_samplers) + ")").c_str()) - ("star-p-replacement", po::value(&(opts.star_p_replacement)), ("Probability of taking replacement step (stellar fit) (default: " + to_string(opts.star_p_replacement) + ")").c_str()) - ("no-stellar-priors", "Turn off priors for individual stars.") - ("min-EBV", po::value(&(opts.min_EBV)), ("Minimum stellar E(B-V) (default: " + to_string(opts.min_EBV) + ")").c_str()) - - ("mean-RV", po::value(&(opts.mean_RV)), ("Mean R_V (per star) (default: " + to_string(opts.mean_RV) + ")").c_str()) - ("sigma-RV", po::value(&(opts.sigma_RV)), ("Variation in R_V (per star) (default: " + to_string(opts.sigma_RV) + ", interpreted as no variance)").c_str()) - - ("regions", po::value(&(opts.N_regions)), ("# of piecewise-linear regions in l.o.s. extinction profile (default: " + to_string(opts.N_regions) + ")").c_str()) - ("los-steps", po::value(&(opts.los_steps)), ("# of MCMC steps in l.o.s. fit (per sampler) (default: " + to_string(opts.los_steps) + ")").c_str()) - ("los-samplers", po::value(&(opts.los_samplers)), ("# of samplers per dimension (l.o.s. fit) (default: " + to_string(opts.los_samplers) + ")").c_str()) - ("los-p-replacement", po::value(&(opts.los_p_replacement)), ("Probability of taking replacement step (l.o.s. fit) (default: " + to_string(opts.los_p_replacement) + ")").c_str()) - - ("clouds", po::value(&(opts.N_clouds)), ("# of clouds along the line of sight (default: " + to_string(opts.N_clouds) + ")\n" - "Setting this option causes the sampler to also fit a discrete " - "cloud model of the l.o.s. extinction profile.").c_str()) - ("cloud-steps", po::value(&(opts.cloud_steps)), ("# of MCMC steps in cloud fit (per sampler) (default: " + to_string(opts.cloud_steps) + ")").c_str()) - ("cloud-samplers", po::value(&(opts.cloud_samplers)), ("# of samplers per dimension (cloud fit) (default: " + to_string(opts.cloud_samplers) + ")").c_str()) - ("cloud-p-replacement", po::value(&(opts.cloud_p_replacement)), ("Probability of taking replacement step (cloud fit) (default: " + to_string(opts.cloud_p_replacement) + ")").c_str()) - - ("disk-prior", "Assume that dust density roughly traces stellar disk density.") - ("SFD-prior", "Use SFD E(B-V) as a prior on the total extinction in each pixel.") - ("SFD-subpixel", "Use SFD E(B-V) as a subpixel template for the angular variation in reddening.") - ("evidence-cut", po::value(&(opts.ev_cut)), ("Delta lnZ to use as threshold for including star " - "in l.o.s. fit (default: " + to_string(opts.ev_cut) + ")").c_str()) - - ("runs", po::value(&(opts.N_runs)), ("# of times to run each chain (to check\n" - "for non-convergence) (default: " + to_string(opts.N_runs) + ")").c_str()) - - ("LF-file", po::value(&(opts.LF_fname)), "File containing stellar luminosity function.") - ("template-file", po::value(&(opts.template_fname)), "File containing stellar color templates.") - ("ext-file", po::value(&(opts.ext_model_fname)), "File containing extinction coefficients.") - ; - - po::options_description gal_desc("Galactic Structural Parameters (all distances in pc)"); - gal_desc.add_options() - ("R0", po::value(&(opts.gal_struct_params.R0)), ("Solar Galactocentric distance (default: " + to_string(opts.gal_struct_params.R0) + ")").c_str()) - ("Z0", po::value(&(opts.gal_struct_params.Z0)), ("Solar height above Galactic midplane (default: " + to_string(opts.gal_struct_params.Z0) + ")").c_str()) - - ("H_thin", po::value(&(opts.gal_struct_params.H1)), ("Thin-disk scale height (default: " + to_string(opts.gal_struct_params.H1) + ")").c_str()) - ("L_thin", po::value(&(opts.gal_struct_params.L1)), ("Thin-disk scale length (default: " + to_string(opts.gal_struct_params.L1) + ")").c_str()) - - ("f_thick", po::value(&(opts.gal_struct_params.f_thick)), ("Thick-disk fraction, defined locally (default: " + to_string(opts.gal_struct_params.f_thick) + ")").c_str()) - ("H_thick", po::value(&(opts.gal_struct_params.H2)), ("Thick-disk scale height (default: " + to_string(opts.gal_struct_params.H2) + ")").c_str()) - ("L_thick", po::value(&(opts.gal_struct_params.L2)), ("Thin-disk scale length (default: " + to_string(opts.gal_struct_params.L2) + ")").c_str()) - - ("L_epsilon", po::value(&(opts.gal_struct_params.L_epsilon)), ("Disk softening scale (default: " + to_string(opts.gal_struct_params.L_epsilon) + ")").c_str()) - - ("f_halo", po::value(&(opts.gal_struct_params.fh)), ("Halo fraction, defined locally (default: " + to_string(opts.gal_struct_params.fh) + ")").c_str()) - ("q_halo", po::value(&(opts.gal_struct_params.qh)), ("Halo flattening parameter (default: " + to_string(opts.gal_struct_params.qh) + ")").c_str()) - ("n_halo", po::value(&(opts.gal_struct_params.nh)), ("Halo density slope (default: " + to_string(opts.gal_struct_params.nh) + ")").c_str()) - ("R_break", po::value(&(opts.gal_struct_params.R_br)), ("Halo break radius (default: " + to_string(opts.gal_struct_params.R_br) + ")").c_str()) - ("n_halo_outer", po::value(&(opts.gal_struct_params.nh_outer)), ("Halo outer density slope, past break (default: " + to_string(opts.gal_struct_params.nh_outer) + ")").c_str()) - - ("H_ISM", po::value(&(opts.gal_struct_params.H_ISM)), ("Dust scale height (default: " + to_string(opts.gal_struct_params.H_ISM) + ")").c_str()) - ("L_ISM", po::value(&(opts.gal_struct_params.L_ISM)), ("Dust scale length (default: " + to_string(opts.gal_struct_params.L_ISM) + ")").c_str()) - ("dH_dR_ISM", po::value(&(opts.gal_struct_params.dH_dR_ISM)), ("Dust flare slope (default: " + to_string(opts.gal_struct_params.dH_dR_ISM) + ")").c_str()) - ("R_flair_ISM", po::value(&(opts.gal_struct_params.R_flair_ISM)), ("Dust flair slope (default: " + to_string(opts.gal_struct_params.R_flair_ISM) + ")").c_str()) - - ("mu_FeH_inf", po::value(&(opts.gal_struct_params.mu_FeH_inf)), ("Disk metallicity at large elevation above midplane (default: " + to_string(opts.gal_struct_params.mu_FeH_inf) + ")").c_str()) - ("delta_mu_FeH", po::value(&(opts.gal_struct_params.delta_mu_FeH)), ("Disk metallicity at midplane, minus metallicity at large elevation (default: " + to_string(opts.gal_struct_params.delta_mu_FeH) + ")").c_str()) - ("H_mu_FeH", po::value(&(opts.gal_struct_params.H_mu_FeH)), ("Disk metallicity scale height (default: " + to_string(opts.gal_struct_params.H_mu_FeH) + ")").c_str()) - ; - config_desc.add(gal_desc); - - po::options_description generic_desc(std::string("Usage: ") + argv[0] + " [Input filename] [Output filename] \n\nCommandline Options"); - generic_desc.add_options() - ("help", "Display this help message") - ("show-config", "Display configuration-file options") - ("version", "Display version number") - - ("input", po::value(&(opts.input_fname)), "Input HDF5 filename (contains stellar photometry)") - ("output", po::value(&(opts.output_fname)), "Output HDF5 filename (MCMC output and smoothed probability surfaces)") - - ("config", po::value(&config_fname), "Configuration file containing additional options.") - - ("test-los", "Allow user to test specific line-of-sight profiles manually.") - ; - - po::options_description dual_desc("Dual Options (both commandline and configuration file)"); - dual_desc.add_options() - ("save-surfs", "Save probability surfaces.") - ("clobber", "Overwrite existing output. Otherwise, will\n" - "only process pixels with incomplete output.") - ("verbosity", po::value(&(opts.verbosity)), ("Level of verbosity (0 = minimal, 2 = highest) (default: " + to_string(opts.verbosity) + ")").c_str()) - ("threads", po::value(&(opts.N_threads)), ("# of threads to run on (default: " + to_string(opts.N_threads) + ")").c_str()) - ; - - po::positional_options_description pd; - pd.add("input", 1).add("output", 1); - - - // Agglomerate different categories of options - po::options_description cmdline_desc; - cmdline_desc.add(generic_desc).add(dual_desc); - - po::options_description config_all_desc; - config_all_desc.add(config_desc).add(dual_desc); - - - // Parse options - - po::variables_map vm; - po::store(po::command_line_parser(argc, argv).options(cmdline_desc).positional(pd).run(), vm); - po::notify(vm); - - if(config_fname != "NONE") { - std::ifstream f_config(config_fname.c_str()); - if(!f_config) { - cerr << "Could not open " << config_fname << endl; - cerr << "Quitting." << endl; - return 0; - } - po::store(po::parse_config_file(f_config, config_all_desc, false), vm); - f_config.close(); - - po::notify(vm); - } - - - - if(vm.count("help")) { - cout << cmdline_desc << endl; - return 0; - } - - if(vm.count("show-config")) { - cout << config_all_desc << endl; - return 0; - } - - if(vm.count("version")) { - cout << "git commit " << GIT_BUILD_VERSION << endl; - return 0; - } - - if(vm.count("synthetic")) { opts.synthetic = true; } - if(vm.count("save-surfs")) { opts.save_surfs = true; } - if(vm.count("no-stellar-priors")) { opts.star_priors = false; } - if(vm.count("disk-prior")) { opts.disk_prior = true; } - if(vm.count("SFD-prior")) { opts.SFD_prior = true; } - if(vm.count("SFD-subpixel")) { opts.SFD_subpixel = true; } - if(vm.count("clobber")) { opts.clobber = true; } - if(vm.count("test-los")) { opts.test_mode = true; } - - - // Convert error floor to mags - opts.err_floor /= 1000.; - - if(opts.input_fname == "NONE") { - cerr << "Input filename required." << endl << endl; - cerr << cmdline_desc << endl; - return -1; - } - if(opts.output_fname == "NONE") { - cerr << "Output filename required." << endl << endl; - cerr << cmdline_desc << endl; - return -1; - } - - if(opts.N_regions != 0) { - if(120 % (opts.N_regions) != 0) { - cerr << "# of regions in extinction profile must divide 120 without remainder." << endl; - return -1; - } - } - - return 1; +int los_workflow(TProgramOpts &opts, int argc, char **argv) { + /* + * Uses pre-computed stellar posterior densities + * to determine the l.o.s. reddening. + */ + + + /* + * MCMC Options + */ + + TMCMCOptions cloud_options(opts.cloud_steps, opts.cloud_samplers, opts.cloud_p_replacement, opts.N_runs); + TMCMCOptions los_options(opts.los_steps, opts.los_samplers, opts.los_p_replacement, opts.N_runs); + + TMCMCOptions discrete_los_options(opts.discrete_steps, 1, 0., opts.N_runs); // TODO: Create commandline options for this + + + /* + * Construct models + */ + + TExtinctionModel ext_model(opts.ext_model_fname); + + TEBVSmoothing EBV_smoothing(opts.smoothing_alpha_coeff, + opts.smoothing_beta_coeff, + opts.pct_smoothing_min, + opts.pct_smoothing_max); + + /* + * Execute + */ + + omp_set_num_threads(opts.N_threads); + + // Get list of pixels in input file + vector pix_name; + get_input_pixels(opts.input_fname, pix_name, "/stellar_pdfs"); + cout << "# " << pix_name.size() << " pixels in input file." << endl << endl; + + // Get (l,b), (nside, healpix index), EBV estimate of each pixel + vector pix_l, pix_b, pix_EBV; + vector pix_nside; + vector pix_idx; + get_pixel_props( + opts.input_fname, + pix_name, + pix_l, pix_b, pix_EBV, + pix_nside, pix_idx, + "/stellar_pdfs" + ); + + // Remove the output file + if(opts.clobber) { + remove(opts.output_fname.c_str()); + } + + H5::Exception::dontPrint(); + + // Run each pixel + timespec t_start, t_mid, t_end; + + double t_tot, t_star; + unsigned int pixel_list_no = 0; + + for(vector::iterator it = pix_name.begin(); it != pix_name.end(); ++it, pixel_list_no++) { + clock_gettime(CLOCK_MONOTONIC, &t_start); + + cout << "# Pixel: " << *it + << " (" << pixel_list_no + 1 << " of " << pix_name.size() << ")" + << endl; + + double l = pix_l.at(pixel_list_no); + double b = pix_b.at(pixel_list_no); + double EBV = pix_EBV.at(pixel_list_no); + uint32_t nside = pix_nside.at(pixel_list_no); + uint32_t hpidx = pix_idx.at(pixel_list_no); + + // Load input photometry + TGalacticLOSModel los_model( + l, b, + opts.gal_struct_params + ); + + cout << "# HEALPix index: " << hpidx + << " (nside = " << nside << ")" << endl; + cout << "# (l, b) = " + << l << ", " << b << endl; + if(opts.SFD_prior) { + cout << "# E(B-V)_SFD = " << EBV << endl; + } + + // Load surfaces + std::stringstream dset_name; + dset_name << "/stellar_pdfs/" << *it << "/stellar_pdfs"; + std::unique_ptr img_stack = read_img_stack( + opts.input_fname, + dset_name.str() + ); + + unsigned int n_stars = img_stack->N_images; + + cout << "# " << n_stars << " stars in pixel" << endl; + + // Check if this pixel has already been fully processed + if(!(opts.clobber)) { + bool process_pixel = false; + + std::unique_ptr out_file = H5Utils::openFile( + opts.output_fname, + H5Utils::READ | H5Utils::WRITE | H5Utils::DONOTCREATE + ); + + if(!out_file) { + process_pixel = true; + + //cout << "File does not exist" << endl; + } else { + //cout << "File exists" << endl; + //stringstream group_name; + //group_name << stellar_data.healpix_index; + //group_name << stellar_data.nside << "-" << stellar_data.healpix_index; + + std::unique_ptr pix_group = H5Utils::openGroup( + *out_file, + *it, + H5Utils::READ | H5Utils::WRITE | H5Utils::DONOTCREATE + ); + + if(!pix_group) { + process_pixel = true; + } else { + //cout << "Group exists" << endl; + + if(opts.force_pix.size() != 0) { + std::stringstream pix_spec_ss; + pix_spec_ss << nside << "-" << hpidx; + std::string pix_spec_str = pix_spec_ss.str(); + for(auto const &s : opts.force_pix) { + if(pix_spec_str == s) { + std::cerr << "Force-reprocessing pixel " << s << std::endl; + process_pixel = true; + break; + } + } + } + + if((!process_pixel) && (opts.discrete_los)) { + if(!H5Utils::dataset_exists("discrete-los", *pix_group)) { + process_pixel = true; + } + } + + // If pixel is missing data, remove it, so that it can be regenerated + if(process_pixel) { + try { + out_file->unlink(*it); + } catch(H5::FileIException unlink_err) { + cout << "Unable to remove group: '" << *it << "'" + << endl; + } + } + } + } + + if(!process_pixel) { + cout << "# Pixel is already present in output. Skipping." + << endl << endl; + + continue; // All information is already present in output file + } + } + + clock_gettime(CLOCK_MONOTONIC, &t_mid); + + // Tag output pixel with HEALPix nside and index + stringstream group_name; + group_name << "/" << *it; + + try { + H5Utils::add_watermark(opts.output_fname, group_name.str(), "nside", nside); + H5Utils::add_watermark(opts.output_fname, group_name.str(), "healpix_index", hpidx); + H5Utils::add_watermark(opts.output_fname, group_name.str(), "l", l); + H5Utils::add_watermark(opts.output_fname, group_name.str(), "b", b); + H5Utils::add_watermark(opts.output_fname, group_name.str(), "n_stars", n_stars); + } catch(H5::AttributeIException err_att_exists) { } + + // Sample discrete l.o.s. model + if(opts.discrete_los) { + std::unique_ptr neighbor_pixels; + + if((opts.neighbor_lookup_fname != "NONE") && + (opts.pixel_lookup_fname != "NONE") && + (opts.output_fname_pattern != "NONE")) + { + // Load information on neighboring pixels + cout << "Loading information on neighboring pixels ..." << endl; + neighbor_pixels = std::make_unique( + nside, + hpidx, + opts.neighbor_lookup_fname, + opts.pixel_lookup_fname, + opts.output_fname_pattern, + 1000); + + if(!neighbor_pixels->data_loaded()) { + cerr << "Failed to load neighboring pixels! Aborting." + << endl; + return 1; + } + + // Calculate covariance matrices tying + // pixels together at each distance + neighbor_pixels->init_covariance( + opts.correlation_scale, + opts.d_soft, + opts.gamma_soft); + } + + TDiscreteLosMcmcParams discrete_los_params( + std::move(img_stack), + std::move(neighbor_pixels), + 1, 1, + opts.verbosity + ); + discrete_los_params.initialize_priors( + los_model, + opts.log_Delta_EBV_floor, + opts.log_Delta_EBV_ceil, + opts.sigma_log_Delta_EBV, + opts.verbosity + ); + + std::vector neighbor_sample; + + if(discrete_los_params.neighbor_pixels) { + cout << "Initializing dominant distances ..." << endl; + discrete_los_params.neighbor_pixels->init_dominant_dist(opts.verbosity); + + //cout << "Resampling neighboring pixels ..." << endl; + //sample_neighbors(*(discrete_los_params.neighbor_pixels), opts.verbosity); + //sample_neighbors_pt( + // *(discrete_los_params.neighbor_pixels), + // neighbor_sample, + // opts.verbosity + //); + } + + cout << "Sampling line of sight discretely ..." << endl; + sample_los_extinction_discrete( + opts.output_fname, + *it, + discrete_los_options, + discrete_los_params, + neighbor_sample, + opts.dsc_samp_settings, + opts.verbosity + ); + cout << "Done with discrete sampling." << endl; + } + + clock_gettime(CLOCK_MONOTONIC, &t_end); + t_tot = (t_end.tv_sec - t_start.tv_sec) + + 1.e-9 * (t_end.tv_nsec - t_start.tv_nsec); + t_star = (t_mid.tv_sec - t_start.tv_sec) + + 1.e-9 * (t_mid.tv_nsec - t_start.tv_nsec); + + try { + H5Utils::add_watermark(opts.output_fname, group_name.str(), "t_tot", (float)t_tot); + H5Utils::add_watermark(opts.output_fname, group_name.str(), "t_star", (float)t_star); + } catch(H5::AttributeIException err_att_exists) { } + + if(opts.verbosity >= 1) { + cout << endl + << "===================================================" + << endl; + } + cout << "# Time elapsed for pixel: " + << setprecision(2) << t_tot + << " s (" << setprecision(2) + << t_tot / (double)(n_stars) + << " s / star)" << endl; + cout << "# Percentage of time spent on l.o.s. fit: " + << setprecision(2) << 100. * (t_tot - t_star) / t_tot + << " %" << endl; + if(opts.verbosity >= 1) { + cout << "===================================================" + << endl; + } + cout << endl; + } + + /* + * Add additional metadata to output file + */ + try { + string watermark = GIT_BUILD_VERSION; + H5Utils::add_watermark( + opts.output_fname, "/", + "bayestar git commit", + watermark + ); + } catch(H5::AttributeIException err_att_exists) { } + + stringstream commandline_args; + for(int i=0; i( + opts.output_fname, "/", + "commandline invocation", + commandline_args_str + ); + } catch(H5::AttributeIException err_att_exists) { } + + return 0; } int main(int argc, char **argv) { - gsl_set_error_handler_off(); - - /* - * Parse commandline arguments - */ - - TProgramOpts opts; - int parse_res = get_program_opts(argc, argv, opts); - if(parse_res <= 0) { return parse_res; } - - time_t tmp_time = time(0); - char * dt = ctime(&tmp_time); - cout << "# Start time: " << dt; - - timespec prog_start_time; - clock_gettime(CLOCK_MONOTONIC, &prog_start_time); - - - /* - * MCMC Options - */ - - TMCMCOptions star_options(opts.star_steps, opts.star_samplers, opts.star_p_replacement, opts.N_runs); - TMCMCOptions cloud_options(opts.cloud_steps, opts.cloud_samplers, opts.cloud_p_replacement, opts.N_runs); - TMCMCOptions los_options(opts.los_steps, opts.los_samplers, opts.los_p_replacement, opts.N_runs); - - - /* - * Construct models - */ - - TStellarModel *emplib = NULL; - TSyntheticStellarModel *synthlib = NULL; - if(opts.synthetic) { - synthlib = new TSyntheticStellarModel(DATADIR "PS1templates.h5"); - } else { - emplib = new TStellarModel(opts.LF_fname, opts.template_fname); - } - TExtinctionModel ext_model(opts.ext_model_fname); - - - /* - * Execute - */ - - omp_set_num_threads(opts.N_threads); - - // Get list of pixels in input file - vector pix_name; - get_input_pixels(opts.input_fname, pix_name); - cout << "# " << pix_name.size() << " pixels in input file." << endl << endl; - - // Remove the output file - if(opts.clobber) { - remove(opts.output_fname.c_str()); - } - - H5::Exception::dontPrint(); - - // Run each pixel - timespec t_start, t_mid, t_end; - - double t_tot, t_star; - unsigned int pixel_list_no = 0; - - for(vector::iterator it = pix_name.begin(); it != pix_name.end(); ++it, pixel_list_no++) { - clock_gettime(CLOCK_MONOTONIC, &t_start); - - cout << "# Pixel: " << *it << " (" << pixel_list_no + 1 << " of " << pix_name.size() << ")" << endl; - - TStellarData stellar_data(opts.input_fname, *it, opts.err_floor); - TGalacticLOSModel los_model(stellar_data.l, stellar_data.b, opts.gal_struct_params); - - cout << "# HEALPix index: " << stellar_data.healpix_index << " (nside = " << stellar_data.nside << ")" << endl; - cout << "# (l, b) = " << stellar_data.l << ", " << stellar_data.b << endl; - if(opts.SFD_prior) { cout << "# E(B-V)_SFD = " << stellar_data.EBV << endl; } - cout << "# " << stellar_data.star.size() << " stars in pixel" << endl; - - - // Check if this pixel has already been fully processed - if(!(opts.clobber)) { - bool process_pixel = false; - - H5::H5File *out_file = H5Utils::openFile(opts.output_fname, H5Utils::READ | H5Utils::WRITE | H5Utils::DONOTCREATE); - - if(out_file == NULL) { - process_pixel = true; - - //cout << "File does not exist" << endl; - } else { - //cout << "File exists" << endl; - //stringstream group_name; - //group_name << stellar_data.healpix_index; - //group_name << stellar_data.nside << "-" << stellar_data.healpix_index; - - H5::Group *pix_group = H5Utils::openGroup(out_file, *it, H5Utils::READ | H5Utils::WRITE | H5Utils::DONOTCREATE); - - if(pix_group == NULL) { - process_pixel = true; - } else { - //cout << "Group exists" << endl; - - if(!H5Utils::dataset_exists("stellar chains", pix_group)) { - process_pixel = true; - } else { - if(opts.save_surfs) { - if(!H5Utils::dataset_exists("stellar pdfs", pix_group)) { - process_pixel = true; - } - } - - if(!process_pixel) { - if(opts.N_clouds != 0) { - if(!H5Utils::dataset_exists("clouds", pix_group)) { - process_pixel = true; - } - } - } - - if(!process_pixel) { - if(opts.N_regions != 0) { - if(!H5Utils::dataset_exists("los", pix_group)) { - process_pixel = true; - } - } - } - } - - delete pix_group; - - // If pixel is missing data, remove it, so that it can be regenerated - if(process_pixel) { - try { - out_file->unlink(*it); - } catch(H5::FileIException unlink_err) { - cout << "Unable to remove group: '" << *it << "'" << endl; - } - } - } - - delete out_file; - } - - if(!process_pixel) { - cout << "# Pixel is already present in output. Skipping." << endl << endl; - - continue; // All information is already present in output file - } - } - - // Prepare data structures for stellar parameters - TImgStack img_stack(stellar_data.star.size()); - vector conv; - vector lnZ; - - bool gatherSurfs = (opts.N_regions || opts.N_clouds || opts.save_surfs); - - // Sample individual stars - if(opts.synthetic) { - sample_indiv_synth(opts.output_fname, star_options, los_model, *synthlib, ext_model, - stellar_data, img_stack, conv, lnZ, opts.sigma_RV, - opts.min_EBV, opts.save_surfs, gatherSurfs, opts.verbosity); - } else { - sample_indiv_emp(opts.output_fname, star_options, los_model, *emplib, ext_model, - stellar_data, img_stack, conv, lnZ, opts.mean_RV, opts.sigma_RV, opts.min_EBV, - opts.save_surfs, gatherSurfs, opts.star_priors, opts.verbosity); - } - - clock_gettime(CLOCK_MONOTONIC, &t_mid); - - // Tag output pixel with HEALPix nside and index - stringstream group_name; - group_name << "/" << *it; - - try { - H5Utils::add_watermark(opts.output_fname, group_name.str(), "nside", stellar_data.nside); - H5Utils::add_watermark(opts.output_fname, group_name.str(), "healpix_index", stellar_data.healpix_index); - } catch(H5::AttributeIException err_att_exists) { } - - // Filter based on convergence and lnZ - assert(conv.size() == lnZ.size()); - vector keep; - vector lnZ_filtered; - for(vector::iterator it_lnZ = lnZ.begin(); it_lnZ != lnZ.end(); ++it_lnZ) { - if(!isnan(*it_lnZ) && !is_inf_replacement(*it_lnZ)) { - lnZ_filtered.push_back(*it_lnZ); - } - } - double lnZmax = percentile_const(lnZ_filtered, 95.0); - if(opts.verbosity >= 2) { cout << "# ln(Z)_95pct = " << lnZmax << endl; } - - bool tmpFilter; - size_t nFiltered = 0; - std::vector subpixel; - lnZ_filtered.clear(); - for(size_t n=0; n lnZmax - (25. + opts.ev_cut)) && !isnan(lnZ[n]) && !is_inf_replacement(lnZ[n]); - keep.push_back(tmpFilter); - if(tmpFilter) { - subpixel.push_back(stellar_data.star[n].EBV); - lnZ_filtered.push_back(lnZ[n] - lnZmax); - } else { - nFiltered++; - } - } - if(gatherSurfs) { img_stack.cull(keep); } - - // Fit line-of-sight extinction profile - if((nFiltered < conv.size()) && ((opts.N_clouds != 0) || (opts.N_regions != 0))) { - cout << "# of stars filtered: " << nFiltered << " of " << conv.size(); - cout << " (" << 100. * (double)nFiltered / (double)(conv.size()) << " %)" << endl; - - double p0 = exp(-5. - opts.ev_cut); - double EBV_max = -1.; - if(opts.SFD_prior) { - if(opts.SFD_subpixel) { - EBV_max = 1.; - } else { - EBV_max = stellar_data.EBV; - } - } - TLOSMCMCParams params(&img_stack, lnZ_filtered, p0, opts.N_runs, opts.N_threads, opts.N_regions, EBV_max); - if(opts.SFD_subpixel) { params.set_subpixel_mask(subpixel); } - - if(opts.test_mode) { - test_extinction_profiles(params); - } - - if(opts.N_clouds != 0) { - sample_los_extinction_clouds(opts.output_fname, *it, cloud_options, params, opts.N_clouds, opts.verbosity); - } - if(opts.N_regions != 0) { - params.gen_guess_covariance(1.); // Covariance matrix for guess has (anti-)correlation length of 1 distance bin - if(opts.disk_prior) { - params.calc_Delta_EBV_prior(los_model, stellar_data.EBV, opts.verbosity); - } - sample_los_extinction(opts.output_fname, *it, los_options, params, opts.verbosity); - } - } - - clock_gettime(CLOCK_MONOTONIC, &t_end); - t_tot = (t_end.tv_sec - t_start.tv_sec) + 1.e-9 * (t_end.tv_nsec - t_start.tv_nsec); - t_star = (t_mid.tv_sec - t_start.tv_sec) + 1.e-9 * (t_mid.tv_nsec - t_start.tv_nsec); - - if(opts.verbosity >= 1) { - cout << endl; - cout << "===================================================" << endl; - } - cout << "# Time elapsed for pixel: "; - cout << setprecision(2) << t_tot; - cout << " s (" << setprecision(2) << t_tot / (double)(stellar_data.star.size()) << " s / star)" << endl; - cout << "# Percentage of time spent on l.o.s. fit: "; - cout << setprecision(2) << 100. * (t_tot - t_star) / t_tot << " %" << endl; - if(opts.verbosity >= 1) { - cout << "===================================================" << endl; - } - cout << endl; - } - - - /* - * Add additional metadata to output file - */ - try { - string watermark = GIT_BUILD_VERSION; - H5Utils::add_watermark(opts.output_fname, "/", "bayestar git commit", watermark); - } catch(H5::AttributeIException err_att_exists) { } - - stringstream commandline_args; - for(int i=0; i(opts.output_fname, "/", "commandline invocation", commandline_args_str); - } catch(H5::AttributeIException err_att_exists) { } - - - /* - * Cleanup - */ - - if(synthlib != NULL) { delete synthlib; } - if(emplib != NULL) { delete emplib; } - - tmp_time = time(0); - dt = ctime(&tmp_time); - cout << "# End time: " << dt; - - timespec prog_end_time; - clock_gettime(CLOCK_MONOTONIC, &prog_end_time); - double prog_ss = prog_end_time.tv_sec - prog_start_time.tv_sec + 1.e-9 * (prog_end_time.tv_nsec - prog_start_time.tv_nsec); - int prog_mm = floor(prog_ss / 60.); - int prog_hh = floor(prog_mm / 60.); - int prog_dd = floor(prog_hh / 24.); - prog_hh = prog_hh % 24; - prog_mm = prog_mm % 60; - prog_ss -= 60. * prog_mm + 3600. * prog_hh + 3600.*24. * prog_dd; - cout << "# Elapsed time: " << prog_dd << " d " << prog_hh << " h " << prog_mm << " m " << prog_ss << " s" << endl; - - - return 0; + gsl_set_error_handler_off(); + + /* + * Parse commandline arguments + */ + + TProgramOpts opts; + int parse_res = get_program_opts(argc, argv, opts); + if(parse_res <= 0) { return parse_res; } + + time_t tmp_time = time(0); + char * dt = ctime(&tmp_time); + cout << "# Start time: " << dt; + + timespec prog_start_time; + clock_gettime(CLOCK_MONOTONIC, &prog_start_time); + + int res; + if(opts.load_surfs) { + // Use pre-computed stellar posterior densities + // to determine l.o.s. reddening + res = los_workflow(opts, argc, argv); + } else { + // Determine stellar posterior densities, + // then determine l.o.s. reddening + res = full_workflow(opts, argc, argv); + } + + tmp_time = time(0); + dt = ctime(&tmp_time); + cout << "# End time: " << dt; + + timespec prog_end_time; + clock_gettime(CLOCK_MONOTONIC, &prog_end_time); + double prog_ss = prog_end_time.tv_sec - prog_start_time.tv_sec + + 1.e-9 * (prog_end_time.tv_nsec - prog_start_time.tv_nsec); + int prog_mm = floor(prog_ss / 60.); + int prog_hh = floor(prog_mm / 60.); + int prog_dd = floor(prog_hh / 24.); + prog_hh = prog_hh % 24; + prog_mm = prog_mm % 60; + prog_ss -= 60. * prog_mm + 3600. * prog_hh + 3600.*24. * prog_dd; + cout << "# Elapsed time: " + << prog_dd << " d " + << prog_hh << " h " + << prog_mm << " m " + << prog_ss << " s" << endl; + + return res; } diff --git a/src/model.cpp b/src/model.cpp index c03fb7c..b9cac83 100644 --- a/src/model.cpp +++ b/src/model.cpp @@ -1,26 +1,26 @@ /* * model.cpp - * + * * Defines the stellar and galactic models. - * + * * This file is part of bayestar. * Copyright 2012 Gregory Green - * + * * Bayestar is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. - * + * */ #include "model.h" @@ -35,41 +35,44 @@ /**************************************************************************************************************************** - * + * * TGalStructParams - * + * ****************************************************************************************************************************/ TGalStructParams::TGalStructParams() { // Solar position R0 = 8000; Z0 = 25; - + // Thin disk L1 = 2150; H1 = 245; - + // Thick disk f_thick = 0.13; L2 = 3261; H2 = 743; - + // Smoothing radial scale of disk L_epsilon = 500; - + // Halo fh = 0.0030; //0.0051; qh = 0.70; nh = -2.62; R_br = 27800; nh_outer = -3.8; - + + // Smoothing of the halo core + R_epsilon = 500; + // Drimmel & Spergel (2001) H_ISM = 134.4; L_ISM = 2260.; dH_dR_ISM = 0.0148; R_flair_ISM = 4400.; - + // Metallicity mu_FeH_inf = -0.82; delta_mu_FeH = 0.55; @@ -78,15 +81,15 @@ TGalStructParams::TGalStructParams() { /**************************************************************************************************************************** - * + * * TGalacticModel - * + * ****************************************************************************************************************************/ TGalacticModel::TGalacticModel() { TGalStructParams gal_struct_params; set_struct_params(gal_struct_params); - + // IMF and SFR disk_abundance = new TStellarAbundance(0); halo_abundance = new TStellarAbundance(1); @@ -94,7 +97,7 @@ TGalacticModel::TGalacticModel() { TGalacticModel::TGalacticModel(const TGalStructParams& gal_struct_params) { set_struct_params(gal_struct_params); - + disk_abundance = new TStellarAbundance(0); halo_abundance = new TStellarAbundance(1); } @@ -109,19 +112,19 @@ void TGalacticModel::set_struct_params(const TGalStructParams& gal_struct_params // Solar position R0 = gal_struct_params.R0; Z0 = gal_struct_params.Z0; - + // Thin disk L1 = gal_struct_params.L1; H1 = gal_struct_params.H1; - + // Thick disk f_thick = gal_struct_params.f_thick; L2 = gal_struct_params.L2; H2 = gal_struct_params.H2; - + // Smoothing radial scale of disk L_epsilon = gal_struct_params.L_epsilon; - + // Halo fh = gal_struct_params.fh; qh = gal_struct_params.qh; @@ -130,13 +133,13 @@ void TGalacticModel::set_struct_params(const TGalStructParams& gal_struct_params nh_outer = gal_struct_params.nh_outer; fh_outer = fh * pow(R_br/R0, nh - nh_outer); R_epsilon2 = gal_struct_params.R_epsilon * gal_struct_params.R_epsilon; - + // Smooth ISM disk H_ISM = gal_struct_params.H_ISM; L_ISM = gal_struct_params.L_ISM; dH_dR_ISM = gal_struct_params.dH_dR_ISM; R_flair_ISM = gal_struct_params.R_flair_ISM; - + // Metallicity mu_FeH_inf = gal_struct_params.mu_FeH_inf; delta_mu_FeH = gal_struct_params.delta_mu_FeH; @@ -145,7 +148,7 @@ void TGalacticModel::set_struct_params(const TGalStructParams& gal_struct_params double TGalacticModel::rho_halo(double R, double Z) const { double r_eff2 = R*R + (Z/qh)*(Z/qh) + R_epsilon2; - + if(r_eff2 <= R_br*R_br) { return fh*pow(r_eff2/(R0*R0), nh/2.); } else { @@ -155,7 +158,7 @@ double TGalacticModel::rho_halo(double R, double Z) const { double TGalacticModel::rho_disk(double R, double Z) const { double R_eff = sqrt(R*R + L_epsilon*L_epsilon); - + double rho_thin = exp(-(fabs(Z+Z0) - fabs(Z0))/H1 - (R_eff-R0)/L1); double rho_thick = f_thick * exp(-(fabs(Z+Z0) - fabs(Z0))/H2 - (R_eff-R0)/L2); return rho_thin + rho_thick; @@ -164,16 +167,16 @@ double TGalacticModel::rho_disk(double R, double Z) const { double TGalacticModel::rho_ISM(double R, double Z) const { double H = H_ISM; if(R > R_flair_ISM) { H += (R - R_flair_ISM) * dH_dR_ISM; } - + double L_term; if(R > 0.5 * R0) { L_term = exp(-R / L_ISM); } else { L_term = exp(-0.5*R0 / L_ISM - (R - 0.5*R0)*(R - 0.5*R0)/(0.25 * R0*R0)); } - + double sqrt_H_term = cosh((Z+Z0) / H); - + return L_term / (sqrt_H_term * sqrt_H_term); } @@ -184,22 +187,22 @@ double TGalacticModel::mu_FeH_disk(double Z) const { double TGalacticModel::log_p_FeH(double FeH, double R, double Z) const { double f_H = rho_halo(R, Z) / rho_disk(R, Z); - + // Halo double mu_H = -1.46; double sigma_H = 0.3; double P_tmp = f_H * exp(-(FeH-mu_H)*(FeH-mu_H)/(2.*sigma_H*sigma_H)) / (SQRT2PI*sigma_H); - + // Metal-poor disk double mu_D = mu_FeH_disk(Z) - 0.067; double sigma_D = 0.2; P_tmp += 0.63 * (1-f_H) * exp(-(FeH-mu_D)*(FeH-mu_D)/(2.*sigma_D*sigma_D)) / (SQRT2PI*sigma_D); - + // Metal-rich disk double mu_D_poor = mu_D + 0.14; double sigma_D_poor = 0.2; P_tmp += 0.37 * (1-f_H) * exp(-(FeH-mu_D_poor)*(FeH-mu_D_poor)/(2.*sigma_D_poor*sigma_D_poor)) / (SQRT2PI*sigma_D_poor); - + return log(P_tmp); } @@ -209,7 +212,7 @@ double TGalacticModel::p_FeH(double FeH, double R, double Z, int component) cons double mu_D = mu_FeH_disk(Z) - 0.067; const double sigma_D = 0.2; double P_tmp = 0.63 * exp(-(FeH-mu_D)*(FeH-mu_D)/(2.*sigma_D*sigma_D)) / (SQRT2PI*sigma_D); - + // Metal-rich disk const double mu_D_poor = mu_D + 0.14; const double sigma_D_poor = 0.2; @@ -251,12 +254,12 @@ double TGalacticModel::SFR(double tau, int component) const { /**************************************************************************************************************************** - * + * * TGalacticLOSModel - * + * ****************************************************************************************************************************/ -TGalacticLOSModel::TGalacticLOSModel(double _l, double _b) +TGalacticLOSModel::TGalacticLOSModel(double _l, double _b) : TGalacticModel() { init(_l, _b); @@ -282,12 +285,12 @@ void TGalacticLOSModel::init(double _l, double _b) { sin_l = sin(0.0174532925*l); cos_b = cos(0.0174532925*b); sin_b = sin(0.0174532925*b); - + // Precompute interpolation anchors for log(dN/dDM), f_halo and mu_FeH_disk DM_min = 0.; DM_max = 25.; DM_samples = 10000; - + log_dNdmu_arr = new TLinearInterp(DM_min, DM_max, DM_samples); f_halo_arr = new TLinearInterp(DM_min, DM_max, DM_samples); mu_FeH_disk_arr = new TLinearInterp(DM_min, DM_max, DM_samples); @@ -299,7 +302,7 @@ void TGalacticLOSModel::init(double _l, double _b) { log_dNdmu_tmp = log_dNdmu_full(DM_i); (*log_dNdmu_arr)[i] = log_dNdmu_tmp; (*f_halo_arr)[i] = f_halo_full(DM_i); - Z = sin_b * pow10(DM_i/5. + 1.); + Z = sin_b * exp10(DM_i/5. + 1.); (*mu_FeH_disk_arr)[i] = mu_FeH_disk(Z); log_dNdmu_norm += exp(log_dNdmu_tmp - log_dNdmu_0); } @@ -308,10 +311,10 @@ void TGalacticLOSModel::init(double _l, double _b) { } void TGalacticLOSModel::DM_to_RZ(double DM, double& R, double& Z) const { - double d = pow10(DM/5. + 1.); + double d = exp10(DM/5. + 1.); double X = R0 - cos_l*cos_b*d; double Y = -sin_l*cos_b*d; - + Z = sin_b*d; R = sqrt(X*X + Y*Y); } @@ -319,63 +322,63 @@ void TGalacticLOSModel::DM_to_RZ(double DM, double& R, double& Z) const { double TGalacticLOSModel::rho_disk_los(double DM) const { double R, Z; DM_to_RZ(DM, R, Z); - + return rho_disk(R, Z); } double TGalacticLOSModel::rho_halo_los(double DM) const { double R, Z; DM_to_RZ(DM, R, Z); - + return rho_halo(R, Z); } double TGalacticLOSModel::rho_ISM_los(double DM) const { double R, Z; DM_to_RZ(DM, R, Z); - + return rho_ISM(R, Z); } double TGalacticLOSModel::log_dNdmu_full(double DM) const { double R, Z; DM_to_RZ(DM, R, Z); - + double log_rho = log(rho_disk(R,Z) + rho_halo(R,Z)); double log_V = 3.*2.30258509/5. * DM; - + return log_rho + log_V; } double TGalacticLOSModel::f_halo_full(double DM) const { double R, Z; DM_to_RZ(DM, R, Z); - + double rho_halo_tmp = rho_halo(R, Z); double rho_disk_tmp = rho_disk(R, Z); double f_h_tmp = rho_halo_tmp / (rho_disk_tmp + rho_halo_tmp); - + return f_h_tmp; } double TGalacticLOSModel::log_p_FeH_fast(double DM, double FeH, double f_H) const { if(f_H < 0.) { f_H = f_halo(DM); } - + // Halo double mu_H = -1.46; double sigma_H = 0.3; double P_tmp = f_H * exp(-(FeH-mu_H)*(FeH-mu_H)/(2.*sigma_H*sigma_H)) / (SQRT2PI*sigma_H); - + // Metal-poor disk double mu_D = mu_FeH_disk_interp(DM) - 0.067; double sigma_D = 0.2; P_tmp += 0.63 * (1-f_H) * exp(-(FeH-mu_D)*(FeH-mu_D)/(2.*sigma_D*sigma_D)) / (SQRT2PI*sigma_D); - + // Metal-rich disk double mu_D_poor = mu_D + 0.14; double sigma_D_poor = 0.2; P_tmp += 0.37 * (1-f_H) * exp(-(FeH-mu_D_poor)*(FeH-mu_D_poor)/(2.*sigma_D_poor*sigma_D_poor)) / (SQRT2PI*sigma_D_poor); - + return log(P_tmp); } @@ -391,7 +394,7 @@ double TGalacticLOSModel::f_halo(double DM) const { double TGalacticLOSModel::mu_FeH_disk_interp(double DM) const { if((DM < DM_min) || (DM > DM_max)) { - double Z = pow10(DM/5. + 1.) * sin_b; + double Z = exp10(DM/5. + 1.) * sin_b; return mu_FeH_disk(Z); } return (*mu_FeH_disk_arr)(DM); @@ -403,7 +406,7 @@ double TGalacticLOSModel::p_FeH_fast(double DM, double FeH, int component) const double mu_D = mu_FeH_disk_interp(DM) - 0.067; const double sigma_D = 0.2; double P_tmp = 0.63 * exp(-(FeH-mu_D)*(FeH-mu_D)/(2.*sigma_D*sigma_D)) / (SQRT2PI*sigma_D); - + // Metal-rich disk double mu_D_poor = mu_D + 0.14; const double sigma_D_poor = 0.2; @@ -435,6 +438,7 @@ double TGalacticLOSModel::log_prior_emp(double DM, double Mr, double FeH) const double f_H = f_halo(DM); double p = (1. - f_H) * p_FeH_fast(DM, FeH, 0); p += f_H * p_FeH_fast(DM, FeH, 1); + // return log(p); return log_dNdmu(DM) + log(p);// + lnp_Mr(Mr); } @@ -448,7 +452,7 @@ double TGalacticLOSModel::log_prior_emp(const double *x) const { double TGalacticLOSModel::get_log_dNdmu_norm() const { return log_dNdmu_norm; } double TGalacticLOSModel::dA_dmu(double DM) const { - return rho_ISM_los(DM) * pow10(DM / 5.); + return rho_ISM_los(DM) * exp10(DM / 5.); } @@ -460,9 +464,9 @@ void TGalacticLOSModel::get_lb(double &_l, double &_b) const { /**************************************************************************************************************************** - * + * * TSED - * + * ****************************************************************************************************************************/ TSED::TSED() { @@ -542,13 +546,13 @@ TSED& TSED::operator+=(const TSED &rhs) { /**************************************************************************************************************************** - * + * * TStellarModel - * + * ****************************************************************************************************************************/ TStellarModel::TStellarModel(std::string lf_fname, std::string seds_fname) - : sed_interp(NULL), log_lf_interp(NULL) + : sed_interp(NULL), log_lf_interp(NULL) { load_lf(lf_fname); load_seds(seds_fname); @@ -562,42 +566,42 @@ TStellarModel::~TStellarModel() { bool TStellarModel::load_lf(std::string lf_fname) { std::ifstream in(lf_fname.c_str()); if(!in) { std::cerr << "Could not read LF from '" << lf_fname << "'\n"; return false; } - + double Mr0; double dMr = -1; log_lf_norm = 0.; std::vector lf; lf.reserve(3000); - + // Determine length of file std::string line; double Mr, Phi; while(std::getline(in, line)) { if(!line.size()) { continue; } // empty line if(line[0] == '#') { continue; } // comment - + std::istringstream ss(line); ss >> Mr >> Phi; - + if(dMr == -1) { Mr0 = Mr; dMr = 0; } else if(dMr == 0) { dMr = Mr - Mr0; } - + lf.push_back(log(Phi)); log_lf_norm += Phi; } - + double Mr1 = Mr0 + dMr*(lf.size()-1); log_lf_interp = new TLinearInterp(Mr0, Mr1, lf.size()); for(unsigned int i=0; i> Mr >> FeH; - + // Keep track of values needed to get grid spacing and size if(Mr < Mr_min) { Mr_min = Mr; } if(Mr > Mr_max) { Mr_max = Mr; } if(FeH < FeH_min) { FeH_min = FeH; } if(FeH > FeH_max) { FeH_max = FeH; } - + dMr_tmp = fabs(Mr_last - Mr); dFeH_tmp = fabs(FeH_last - FeH); if((dMr_tmp != 0) && (dMr_tmp < dMr)) { dMr = dMr_tmp; } @@ -636,16 +640,16 @@ bool TStellarModel::load_seds(std::string seds_fname) { Mr_last = Mr; FeH_last = FeH; } - + unsigned int N_Mr = (unsigned int)(round((Mr_max - Mr_min) / dMr)) + 1; unsigned int N_FeH = (unsigned int)(round((FeH_max - FeH_min) / dFeH)) + 1; - + // Construct the SED interpolation grid sed_interp = new TBilinearInterp(Mr_min, Mr_max, N_Mr, FeH_min, FeH_max, N_FeH); unsigned int idx; double colors[NBANDS-1]; unsigned int r_index = 1; // TODO: indicate r_index in the template file - + // Now do a second pass to load the SEDs in.clear(); in.seekg(0, std::ios_base::beg); @@ -654,39 +658,42 @@ bool TStellarModel::load_seds(std::string seds_fname) { while(std::getline(in, line)) { if(!line.size()) { continue; } // empty line if(line[0] == '#') { continue; } // comment - + std::istringstream ss(line); ss >> Mr >> FeH; - + idx = sed_interp->get_index(Mr, FeH); - + TSED &sed_tmp = (*sed_interp)[idx]; //sed_tmp.Mr = Mr; //sed_tmp.FeH = FeH; for(unsigned int i=0; i> colors[i]; } - + // Transform colors into absolute magnitudes sed_tmp.absmag[r_index] = Mr; for(int i=r_index-1; i>=0; i--) { sed_tmp.absmag[i] = sed_tmp.absmag[i+1] + colors[i]; } for(int i=r_index+1; i= N_Mr_seds) || (FeH_idx >= N_FeH_seds)) { + std::cerr << " ! Mr_idx = " << Mr_idx + << " , N_Mr_seds = " << N_Mr_seds << std::endl; + std::cerr << " ! FeH_idx = " << FeH_idx + << " , N_FeH_seds = " << N_FeH_seds << std::endl; + return false; + } + + unsigned int flat_idx = sed_interp->get_flat_index(Mr_idx, FeH_idx); + sed = (*sed_interp)[flat_idx]; + sed_interp->get_xy(Mr_idx, FeH_idx, Mr, FeH); + + return true; +} + +unsigned int TStellarModel::get_N_FeH() const { + return N_FeH_seds; +} + +unsigned int TStellarModel::get_N_Mr() const { + return N_Mr_seds; +} + +bool TStellarModel::get_Mr_FeH( + unsigned int Mr_idx, unsigned int FeH_idx, + double& Mr, double& FeH) const +{ + if((Mr_idx >= N_Mr_seds) || (FeH_idx >= N_FeH_seds)) { + std::cerr << " ! Mr_idx = " << Mr_idx + << " , N_Mr_seds = " << N_Mr_seds << std::endl; + std::cerr << " ! FeH_idx = " << FeH_idx + << " , N_FeH_seds = " << N_FeH_seds << std::endl; + return false; + } + sed_interp->get_xy(Mr_idx, FeH_idx, Mr, FeH); + return true; +} + bool TStellarModel::in_model(double Mr, double FeH) { return (Mr > Mr_min_seds) && (Mr < Mr_max_seds) && (FeH > FeH_min_seds) && (FeH < FeH_max_seds); } @@ -723,9 +771,9 @@ double TStellarModel::get_log_lf(double Mr) const { /**************************************************************************************************************************** - * + * * TStellarAbundance - * + * ****************************************************************************************************************************/ // Defaults are from Chabrier (2003) @@ -764,12 +812,12 @@ void TStellarAbundance::set_IMF(double _logM_norm, double _logM_c, double _sigma sigma_logM_2 = _sigma_logM * _sigma_logM; x = _x; A_21 = pow(10, x * logM_norm) * exp( -(logM_norm - logM_c)*(logM_norm - logM_c) / (2.*sigma_logM_2) ); - + // Determine normalization constant s.t. the IMF integrates to unity IMF_norm = sqrt(PI) / 2. * ( 1. + erf( (logM_norm - logM_c) / (SQRT2 * _sigma_logM) ) ); IMF_norm += A_21 * exp( -(x * LN10) * logM_norm ); IMF_norm = 1. / IMF_norm; - + //std::cerr << "# IMF(logM = logM_norm-) = " << IMF(logM_norm - 0.0001) << std::endl; //std::cerr << "# IMF(logM = logM_norm+) = " << IMF(logM_norm + 0.0001) << std::endl; } @@ -779,7 +827,7 @@ void TStellarAbundance::set_SFR(double _A_burst, double _tau_burst, double _sigm tau_burst = _tau_burst; sigma_tau_2 = _sigma_tau * _sigma_tau; tau_max = _tau_max; - + // Determine normalization constant s.t. the SFR integrates to unity SFR_norm = 1. + A_burst * sqrt(PI) / 2. * erf((tau_max - tau_burst) / (SQRT2 * _sigma_tau)); SFR_norm = 1. / SFR_norm; @@ -791,18 +839,18 @@ void TStellarAbundance::set_SFR(double _A_burst, double _tau_burst, double _sigm /**************************************************************************************************************************** - * + * * TSyntheticStellarModel - * + * ****************************************************************************************************************************/ TSyntheticStellarModel::TSyntheticStellarModel(std::string seds_fname) { H5::H5File file(seds_fname.c_str(), H5F_ACC_RDONLY); //cout << "File opened." << endl; - + H5::DataSet dataset = file.openDataSet("PARSEC PS1 Templates"); //cout << "Dataset opened." << endl; - + /* * Memory datatype */ @@ -817,7 +865,7 @@ TSyntheticStellarModel::TSyntheticStellarModel(std::string seds_fname) { mtype.insertMember("M_i", HOFFSET(TSynthSED, M_i), H5::PredType::NATIVE_FLOAT); mtype.insertMember("M_z", HOFFSET(TSynthSED, M_z), H5::PredType::NATIVE_FLOAT); mtype.insertMember("M_y", HOFFSET(TSynthSED, M_y), H5::PredType::NATIVE_FLOAT); - + /* * Dataspace */ @@ -825,17 +873,17 @@ TSyntheticStellarModel::TSyntheticStellarModel(std::string seds_fname) { H5::DataSpace dataspace = dataset.getSpace(); dataspace.getSimpleExtentDims(&length); std::cerr << "# # of elements: " << length << std::endl; - + /* * Read in data */ TSynthSED *data = new TSynthSED[length]; dataset.read(data, mtype); std::cerr << "# Read in " << length << " stellar templates." << std::endl; - + H5::DataSet dim_dataset = file.openDataSet("Dimensions"); std::cerr << "# Opened 'Dimensions' dataset." << std::endl; - + /* * Memory datatype */ @@ -849,18 +897,18 @@ TSyntheticStellarModel::TSyntheticStellarModel(std::string seds_fname) { dim_mtype.insertMember("logtau_max", HOFFSET(TGridDim, logtau_max), H5::PredType::NATIVE_FLOAT); dim_mtype.insertMember("logMass_init_min", HOFFSET(TGridDim, logMass_init_min), H5::PredType::NATIVE_FLOAT); dim_mtype.insertMember("logMass_init_max", HOFFSET(TGridDim, logMass_init_max), H5::PredType::NATIVE_FLOAT); - + hsize_t dim_length; H5::DataSpace dim_dataspace = dim_dataset.getSpace(); dim_dataspace.getSimpleExtentDims(&dim_length); std::cerr << "# # of elements: " << dim_length << std::endl; - + /* * Read in dimensions */ dim_dataset.read(&grid_dim, dim_mtype); std::cerr << "# Read in dimensions." << std::endl; - + /* * Construct trilinear interpolator */ @@ -874,7 +922,7 @@ TSyntheticStellarModel::TSyntheticStellarModel(std::string seds_fname) { empty.absmag[3] = std::numeric_limits::quiet_NaN(); empty.absmag[4] = std::numeric_limits::quiet_NaN(); sed_interp = new TMultiLinearInterp(&min[0], &max[0], &N_points[0], 3, empty); - + std::cerr << "# Constructing interpolating grid over synthetic magnitudes." << std::endl; TSED tmp; bool good_sed; @@ -883,13 +931,13 @@ TSyntheticStellarModel::TSyntheticStellarModel(std::string seds_fname) { Theta[0] = data[i].logMass_init; Theta[1] = data[i].logtau; Theta[2] = log10(data[i].Z/0.019); - + tmp.absmag[0] = data[i].M_g; tmp.absmag[1] = data[i].M_r; tmp.absmag[2] = data[i].M_i; tmp.absmag[3] = data[i].M_z; tmp.absmag[4] = data[i].M_y; - + good_sed = true; for(size_t k=0; k<5; k++) { if((tmp.absmag[k] < -6.) || (tmp.absmag[k] > 25.)) { @@ -901,9 +949,9 @@ TSyntheticStellarModel::TSyntheticStellarModel(std::string seds_fname) { } if(good_sed) { sed_interp->set(&Theta[0], tmp); } } - + std::cerr << "# Done constructing stellar library. " << N_filtered << " stellar templates rejected." << std::endl; - + delete[] data; } @@ -919,23 +967,23 @@ bool TSyntheticStellarModel::get_sed(double logMass, double logtau, double FeH, Theta[0] = logMass; Theta[1] = logtau; Theta[2] = FeH; - + return (*sed_interp)(&Theta[0], sed); } /**************************************************************************************************************************** - * + * * TExtinctionModel - * + * ****************************************************************************************************************************/ TExtinctionModel::TExtinctionModel(std::string A_RV_fname) { std::vector Acoeff; std::vector RV; double tmp; - + // Load in A coefficients for each R_V std::ifstream in(A_RV_fname.c_str()); if(!in) { std::cerr << "Could not read extinction coefficients from '" << A_RV_fname << std::endl; abort(); } @@ -945,23 +993,23 @@ TExtinctionModel::TExtinctionModel(std::string A_RV_fname) { while(std::getline(in, line)) { if(!line.size()) { continue; } // empty line if(line[0] == '#') { continue; } // comment - + std::istringstream ss(line); ss >> tmp; RV.push_back(tmp); if(tmp < RV_min) { RV_min = tmp; } if(tmp > RV_max) { RV_max = tmp; } - + for(unsigned int i=0; i> tmp; - if(ss.fail()) { std::cerr << "Not enough bands in line. Expected " << NBANDS << ". Got " << i << " instead." << std::endl; abort(); } + if(ss.fail()) { std::cerr << "Not enough bands in line. Expected " << NBANDS << ". Got " << i << " instead." << std::endl; abort(); } Acoeff.push_back(tmp); } } - + A_spl = new gsl_spline*[NBANDS]; acc = new gsl_interp_accel*[NBANDS]; - + unsigned int N = RV.size(); double Acoeff_i[N]; double RV_arr[N]; @@ -993,11 +1041,83 @@ bool TExtinctionModel::in_model(double RV) { } +/**************************************************************************************************************************** + * + * TEBVSmoothing + * + ****************************************************************************************************************************/ + +TEBVSmoothing::TEBVSmoothing(double alpha_coeff[2], double beta_coeff[2], + double pct_smoothing_min, double pct_smoothing_max) { + _alpha_coeff[0] = alpha_coeff[0]; + _alpha_coeff[1] = alpha_coeff[1]; + + _beta_coeff[0] = beta_coeff[0]; + _beta_coeff[1] = beta_coeff[1]; + + _pct_smoothing_min = pct_smoothing_min; + _pct_smoothing_max = pct_smoothing_max; + + _healpix_scale = 60.0 * 180.0 / (SQRTPI * SQRT3); +} + +TEBVSmoothing::~TEBVSmoothing() {} + +double TEBVSmoothing::nside_2_arcmin(unsigned int nside) const { + return _healpix_scale / ((double)nside); +} + +// Calculate the percent smoothing (in the E(B-V) direction) to apply to +// individual stellar probability density surfaces. +void TEBVSmoothing::calc_pct_smoothing(unsigned int nside, + double EBV_min, double EBV_max, int n_samples, + std::vector& sigma_pct) const { + double log_scale = log10(nside_2_arcmin(nside)); + + //std::cerr << "scale = " << pow(10., log_scale) << "'" << std::endl; + + //std::cerr << "a_coeff = " << _alpha_coeff[0] << ", " << _alpha_coeff[1] << std::endl; + //std::cerr << "b_coeff = " << _beta_coeff[0] << ", " << _beta_coeff[1] << std::endl; + + double alpha = exp10(_alpha_coeff[0] * log_scale + _alpha_coeff[1]); + double beta = exp10(_beta_coeff[0] * log_scale + _beta_coeff[1]); + + //std::cerr << "alpha = " << alpha << std::endl; + //std::cerr << "beta = " << beta << std::endl; + + double dE = (EBV_max - EBV_min) / (double)(n_samples - 1); + double sigma_pct_tmp; + + sigma_pct.clear(); + + double EBV = EBV_min; + + for(int i=0; i _pct_smoothing_max) { + sigma_pct_tmp = _pct_smoothing_max; + } + + //std::cerr << i << " (" << EBV << "): " << sigma_pct_tmp << std::endl; + + sigma_pct.push_back(sigma_pct_tmp); + } +} + +double TEBVSmoothing::get_pct_smoothing_min() const { return _pct_smoothing_min; } + +double TEBVSmoothing::get_pct_smoothing_max() const { return _pct_smoothing_max; } + + + /**************************************************************************************************************************** - * + * * TLuminosityFunc - * + * ****************************************************************************************************************************/ /* @@ -1015,27 +1135,47 @@ void TLuminosityFunc::load(const std::string &fn) { { if(!line.size()) { continue; } // empty line if(line[0] == '#') { continue; } // comment - + std::istringstream ss(line); ss >> Mr >> Phi; - + if(dMr == -1) { Mr0 = Mr; dMr = 0; } else if(dMr == 0) { dMr = Mr - Mr0; } - + lf.push_back(log(Phi)); log_lf_norm += Phi; } - + double Mr1 = Mr0 + dMr*(lf.size()-1); lf_interp = new TLinearInterp(Mr0, Mr1, lf.size()); for(unsigned int i=0; i *sed_interp; // Bilinear interpolation of stellar SEDs in Mr and FeH - + // Luminosity function library data TLinearInterp *log_lf_interp; double log_lf_norm; - + bool load_lf(std::string lf_fname); bool load_seds(std::string seds_fname); }; @@ -108,19 +121,19 @@ class TStellarAbundance { public: TStellarAbundance(int component); ~TStellarAbundance(); - + double IMF(double logM) const; // Initial mass function double SFR(double tau) const; // Star formation rate - + void set_IMF(double _logM_norm, double _logM_c, double _sigma_logM, double _x); void set_SFR(double _A_burst, double _tau_burst, double _sigma_tau, double _tau_max); - + private: double IMF_norm, SFR_norm; // Normalization constants for IMF and SFR - + // Chabrier (2003) IMF parameters double A_21, logM_norm, logM_c, sigma_logM_2, x; - + // Star formation rate parameters double A_burst, tau_burst, sigma_tau_2, tau_max; }; @@ -131,10 +144,10 @@ class TSyntheticStellarModel { public: TSyntheticStellarModel(std::string seds_fname); ~TSyntheticStellarModel(); - + bool get_sed(const double *MtZ, TSED &sed) const; bool get_sed(double logMass, double logtau, double FeH, TSED &sed); - + private: struct TSynthSED { float Z; @@ -160,7 +173,7 @@ class TSyntheticStellarModel { float logMass_init_min; float logMass_init_max; }; - + TMultiLinearInterp *sed_interp; TGridDim grid_dim; double Theta[3]; @@ -171,10 +184,10 @@ class TExtinctionModel { public: TExtinctionModel(std::string A_RV_fname); ~TExtinctionModel(); - + double get_A(double RV, unsigned int i); // Get A_i(EBV=1), where i is a bandpass bool in_model(double RV); - + private: double RV_min, RV_max; gsl_spline **A_spl; @@ -190,12 +203,12 @@ class TExtinctionModel { TLuminosityFunc(const std::string &fn) : lf_interp(NULL) { load(fn); } ~TLuminosityFunc() { delete lf_interp; } - + // return the LF at position Mr (linear interpolation) double operator()(double Mr) const { return (*lf_interp)(Mr) - log_lf_norm; } - + void load(const std::string &fn); };*/ @@ -207,7 +220,7 @@ struct TGalStructParams { double fh, qh, nh, R_br, nh_outer, R_epsilon; // Halo double mu_FeH_inf, delta_mu_FeH, H_mu_FeH; // Metallicity double H_ISM, L_ISM, dH_dR_ISM, R_flair_ISM; // Smooth ISM disk - + TGalStructParams(); }; @@ -218,34 +231,34 @@ class TGalacticModel { // Set default model parameters TGalacticModel(); TGalacticModel(const TGalStructParams& gal_struct_params); - + ~TGalacticModel(); - + // Set custom model parameters void set_struct_params(const TGalStructParams& gal_struct_params); - + // Stellar density double rho_halo(double R, double Z) const; double rho_disk(double R, double Z) const; - + // ISM density double rho_ISM(double R, double Z) const; - + // Stellar metallicity double mu_FeH_disk(double Z) const; double log_p_FeH(double FeH, double R, double Z) const; - + // Priors (component = {0 for disk, 1 for halo}) double p_FeH(double FeH, double R, double Z, int component) const; double IMF(double logM, int component) const; // Initial mass function double SFR(double tau, int component) const; // Star formation rate //double lnp_Mr(double Mr) const; // Luminosity function - + void set_IMF(int component, double _logM_norm, double _logM_c, double _sigma_logM, double _x); void set_SFR(int component, double _A_burst, double _tau_burst, double _sigma_tau, double _tau_max); - + //void load_lf(std::string lf_fname); - + protected: // Density parameters double R0, Z0; // Solar position @@ -255,16 +268,16 @@ class TGalacticModel { double fh, qh, nh, R_br, nh_outer, R_epsilon2; // Halo (broken power law) double fh_outer; double H_ISM, L_ISM, dH_dR_ISM, R_flair_ISM; - + // Metallicity parameters double mu_FeH_inf; double delta_mu_FeH; double H_mu_FeH; - + // IMF and SFR of Galaxy TStellarAbundance *halo_abundance; TStellarAbundance *disk_abundance; - + // Luminosity Function //TLuminosityFunc *lf; }; @@ -275,65 +288,92 @@ class TGalacticLOSModel : public TGalacticModel { public: // Set default model parameters TGalacticLOSModel(double _l, double _b); - + // Set custom model parameters TGalacticLOSModel(double _l, double _b, const TGalStructParams& gal_struct_params); - + ~TGalacticLOSModel(); - + // Volume element double dV(double DM) const; - + // Stars per unit solid angle per unit distance modulus (up to a normalizing factor) double log_dNdmu(double DM) const; double log_dNdmu_full(double DM) const; - + // Fraction of stars in the halo at a given distance modulus (rho_halo / rho_disk) double f_halo(double DM) const; double f_halo_full(double DM) const; - + // Probability density of star being at given distance modulus with given metallicity double log_p_FeH_fast(double DM, double FeH, double f_H=-1.) const; - + double p_FeH_fast(double DM, double FeH, int component) const; - + double log_prior_synth(double DM, double logM, double logtau, double FeH) const; double log_prior_synth(const double* x) const; - + // Full priors on (DM, Mr, [Fe/H]) for empirical stellar model double log_prior_emp(double DM, double Mr, double FeH) const; double log_prior_emp(const double* x) const; - + // Expected dust reddening, up to normalizing constant double dA_dmu(double DM) const; - + // Convert from distance modulus to R and Z void DM_to_RZ(double DM, double &R, double &Z) const; - + double get_log_dNdmu_norm() const; - + // Densities double rho_disk_los(double DM) const; double rho_halo_los(double DM) const; double rho_ISM_los(double DM) const; - + // Direction of l.o.s. void get_lb(double &l, double &b) const; - + private: double cos_l, sin_l, cos_b, sin_b, l, b; double DM_min, DM_max, DM_samples, log_dNdmu_norm; TLinearInterp *log_dNdmu_arr, *f_halo_arr, *mu_FeH_disk_arr; - + void init(double _l, double _b); - + // Stellar density double rho_halo_interp(double DM) const; double rho_disk_interp(double DM) const; - + // Stellar metallicity double mu_FeH_disk_interp(double DM) const; }; +// A class for calculating the desired percent smoothing in the E(B-V) direction. +class TEBVSmoothing { +public: + TEBVSmoothing(double alpha_coeff[2], double beta_coeff[2], + double pct_smoothing_min, double pct_smoothing_max); + ~TEBVSmoothing(); + + void calc_pct_smoothing(unsigned int nside, + double EBV_min, double EBV_max, int n_samples, + std::vector& sigma_pct) const; + + double get_pct_smoothing_min() const; + double get_pct_smoothing_max() const; + +private: + double _alpha_coeff[2]; // Coefficients for the E^2 coefficient + double _beta_coeff[2]; // Coefficients for the E coefficient + double _pct_smoothing_min; // Minimum smoothing, in percent + double _pct_smoothing_max; // Maximum smoothing, in percent + double _healpix_scale; // Angular scale of a HEALPix nside=1 pixel + + double nside_2_arcmin(unsigned int nside) const; +}; + + +double chi2_parallax(double DM, double parallax, double parallax_err); + -#endif // _MODEL_H__ \ No newline at end of file +#endif // _MODEL_H__ diff --git a/src/neighbor_pixels.cpp b/src/neighbor_pixels.cpp new file mode 100644 index 0000000..d1bf7c0 --- /dev/null +++ b/src/neighbor_pixels.cpp @@ -0,0 +1,1131 @@ +/* + * neighbor_pixels.cpp + * + * Information on neighboring pixels, used to provide prior on + * line-of-sight dust distribution. + * + * This file is part of bayestar. + * Copyright 2018 Gregory Green + * + * Bayestar is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + * + */ + + +#include "neighbor_pixels.h" + + +/**************************************************************************************************************************** + * + * TNeighborPixels + * + ****************************************************************************************************************************/ + + +TNeighborPixels::TNeighborPixels( + uint32_t nside_center, uint32_t pix_idx_center, + const std::string& neighbor_lookup_fname, + const std::string& pixel_lookup_fname, + const std::string& output_fname_pattern, + int n_samples_max) +{ + // Initialize some variables to dummy values + n_pix = 0; + n_samples = 0; + n_dists = 0; + dm_min = -9999.; + dm_max = -9999.; + + // Lookup neighboring pixels + bool status; + status = load_neighbor_list( + nside_center, + pix_idx_center, + neighbor_lookup_fname); + if(!status) { + std::cerr << "Failed to load list of neighbors!" + << std::endl; + loaded = false; + } + + // Lookup pixel locations + std::vector file_idx; + status = lookup_pixel_files(pixel_lookup_fname, file_idx); + if(!status) { + std::cerr << "Failed to load list of output files " + << "containing neighbors!" + << std::endl; + loaded = false; + } + + // Load in neighboring pixels + status = load_neighbor_los(output_fname_pattern, file_idx, n_samples_max); + if(!status) { + std::cerr << "Failed to load neighboring sightline data!" + << std::endl; + loaded = false; + } + + // Successfully loaded data + loaded = true; +} + + +TNeighborPixels::~TNeighborPixels() {} + + +bool TNeighborPixels::data_loaded() const { + return loaded; +} + + +bool TNeighborPixels::load_neighbor_list( + uint32_t nside_center, uint32_t pix_idx_center, + const std::string& neighbor_lookup_fname) +{ + //std::cerr << "Loading " << neighbor_lookup_fname << " ..." + // << std::endl; + std::unique_ptr f = H5Utils::openFile( + neighbor_lookup_fname, + H5Utils::READ); + //std::cerr << "Loaded." << std::endl; + if(!f) { + std::cerr << "Could not open neighbor lookup file!" + << std::endl; + return false; + } + + std::unique_ptr dataset = healtree_get_dataset( + *f, nside_center, pix_idx_center); + if(!dataset) { + std::cerr << "Could not locate neighbor lookup dataset!" + << std::endl; + return false; + } + + // Datatype + H5::DataType dtype = H5::PredType::NATIVE_INT32; + + // Dataspace + hsize_t dims[3]; // (entry, neighbors, nside pix_idx) + H5::DataSpace dataspace = dataset->getSpace(); + dataspace.getSimpleExtentDims(&(dims[0])); + hsize_t length = dims[0] * dims[1] * dims[2]; + + if(dims[2] != 2) { + std::cerr << neighbor_lookup_fname << ": (" + << nside_center << ", " << pix_idx_center + << ") does not have correct shape." + << std::endl; + } + + // Read in dataset + int32_t* buf = new int32_t[length]; + dataset->read(buf, dtype); + + // Search for the correct entry + int entry = 0; + int idx = 0; + int entry_length = dims[1] * dims[2]; + bool located = false; + for(; entry& file_idx) +{ + // Load the lookup table for (nside, pix_idx) -> file_idx + std::unique_ptr f = H5Utils::openFile( + pixel_lookup_fname, + H5Utils::READ); + if(!f) { + std::cerr << "Could not open pixel lookup file!" + << std::endl; + return false; + } + + // Initialize file_idx vector + file_idx.clear(); + file_idx.reserve(nside.size()); + + // Datatype + H5::DataType dtype = H5::PredType::NATIVE_INT32; + + // Loop through neighboring pixels + for(int i=0; i dataset = healtree_get_dataset( + *f, nside.at(i), pix_idx.at(i)); + if(!dataset) { + std::cerr << "Could not locate neighbor lookup dataset (" + << nside.at(i) << ", " << pix_idx.at(i) << ")!" + << std::endl; + return false; + } + + // Dataspace + hsize_t dims[2]; // (entry, nside pix_idx file_idx) + H5::DataSpace dataspace = dataset->getSpace(); + dataspace.getSimpleExtentDims(&(dims[0])); + hsize_t length = dims[0] * dims[1]; + + if(dims[1] != 3) { + std::cerr << pixel_lookup_fname << ": (" + << nside.at(i) << ", " << pix_idx.at(i) + << ") does not have correct shape." + << std::endl; + } + + // Read in dataset + int32_t* buf = new int32_t[length]; + dataset->read(buf, dtype); + + // Search for the correct entry + int entry = 0; + int idx = 0; + int entry_length = dims[1]; + bool located = false; + for(; entry& file_idx, + int n_samples_max) +{ + // Set number of pixels + n_pix = file_idx.size(); + + // Do an argsort of the file indices, so that all the pixels + // that reside in the same file will be handled in a row + std::vector > file_idx_sort; + for(int32_t i=0; i dataset + = H5Utils::openDataSet(*f, dset_name.str()); + if(!dataset) { + std::cerr << "Failed to open dataset " + << dset_name.str() + << " !" << std::endl; + return false; + } + + // Dataspace + hsize_t dims[3]; // (null, GR best samples, prob distances) + H5::DataSpace dataspace = dataset->getSpace(); + dataspace.getSimpleExtentDims(&(dims[0])); + hsize_t length = dims[1] * dims[2]; + + // Set dimensions + if(n_samples == 0) { + n_samples = dims[1] - 2; // (GR, best, samples) + if((n_samples_max > 0) && (n_samples > n_samples_max)) { + n_samples = n_samples_max; + } + } + if(n_dists == 0) { + n_dists = dims[2] - 2; // (likelihood, prior, distances) + } + + // Check dimensions + //if(dims[0] > 1) { + // std::cerr << "Ignoring " << dims[0]-1 << " higher-temperature samples " + // << "in neighboring pixels (" << dset_name.str() << ")" + // << std::endl; + //} + if(dims[1] < n_samples+2) { + std::cerr << "Not enough samples in dataset " + << dset_name.str() + << " !" << std::endl; + return false; + } + if(dims[2] < n_dists+2) { + std::cerr << "Not enough distance bins in dataset " + << dset_name.str() + << " !" << std::endl; + return false; + } + + // Read in dataset + hsize_t mem_shape[1] = {dims[1] * dims[2]}; + H5::DataSpace memspace(1, &(mem_shape[0])); + + hsize_t sel_shape[3] = {1, dims[1], dims[2]}; + hsize_t sel_offset[3] = {0, 0, 0}; + dataspace.selectHyperslab(H5S_SELECT_SET, &(sel_shape[0]), &(sel_offset[0])); + + float* buf = new float[length]; + dataset->read(buf, H5::PredType::NATIVE_FLOAT, memspace, dataspace); + + // Copy into class data structure + if(delta.size() == 0) { + delta.resize(n_pix * n_samples * n_dists); + } + + if(prior.size() == 0) { + prior.resize(n_pix*n_samples); + } + + if(likelihood.size() == 0) { + likelihood.resize(n_pix*n_samples); + } + + if(log_dy.size() == 0) { + log_dy.resize(n_pix*n_samples*n_dists); + } + + if(sum_log_dy.size() == 0) { + sum_log_dy.assign(n_pix*n_samples, 0.); + } + + uint32_t buf_idx; + for(int sample=0; sample 1.e-8) { + // log_dy_tmp = (dy+1.) * std::log(dy+1) - dy * std::log(dy) - 1; + //} else { + // log_dy_tmp = -1.; + //} + set_log_dy(log_dy_tmp, i, sample, dist); + sum_log_dy_tmp += get_log_dy(i, sample, dist); + y_last = y; + } + + set_sum_log_dy(sum_log_dy_tmp, i, sample); + } + + //std::cerr << "Loaded output from " << dset_name.str() + // << std::endl; + + // Load attributes + if(dm_min < -99.) { + dm_min = H5Utils::read_attribute(*dataset, "DM_min"); + } + if(dm_max < -99.) { + dm_max = H5Utils::read_attribute(*dataset, "DM_max"); + } + + double lon_tmp, lat_tmp; + H5::Group group = f->openGroup(group_name.str()); + H5::Attribute att_lon = group.openAttribute("l"); + att_lon.read(H5::PredType::NATIVE_DOUBLE, &lon_tmp); + H5::Attribute att_lat = group.openAttribute("b"); + att_lat.read(H5::PredType::NATIVE_DOUBLE, &lat_tmp); + lon.push_back(lon_tmp); + lat.push_back(lat_tmp); + + //std::cerr << "Loaded attributes related to " << dset_name.str() + // << std::endl; + + delete[] buf; + } + + return true; +} + + +void TNeighborPixels::apply_priors( + const std::vector& mu, + const std::vector& sigma, + double reddening_scale) +{ + // Transforms the stored deltas from raw cumulative reddenings, + // in units of pixels, to scores for the log-normal prior. + // First, cumulative reddenings are transformed into differential + // reddenings. Then, the log is taken, the mean of the log reddening + // is subtracted out, and the result is divided by sigma. + + assert( mu.size() == sigma.size() ); + assert( mu.size() == n_dists ); + + double log_scale = log(reddening_scale); + + for(int dist=n_dists-1; dist != -1; dist--) { + for(int pix=0; pix& mu, + double sigma, + double reddening_scale) +{ + std::vector s; + s.reserve(mu.size()); + for(int i=0; i& mu, + const std::vector& sigma, + double reddening_scale, + int pix, + int sample) +{ + //if(pix == 0) { + // std::cerr << "0 : " << get_delta(pix, sample, 0) << std::endl; + // for(int dist=1; dist" << std::endl; + // for(int dist=0; dist& lon, +// const std::vector& lat, +// const TGalacticLOSModel& gal_los_model) +//{ // n_neighbors = lon.size(); // +// double l, b; +// gal_los_model.get_lb(l, b); +// +// neighbor_lon = std::make_shared >(); +// neighbor_lat = std::make_shared >(); +// neighbor_lon.reserve(n_neighbors+1); +// neighbor_lat.reserve(n_neighbors+1); +// +// neighbor_lon->push_back(l); +// neighbor_lat->push_back(b); +// neighbor_lon->insert(neighbor_lon->end(), lon.begin(), lon.end()); +// neighbor_lat->insert(neighbor_lon->end(), lon.begin(), lon.end()); +// +// // TODO: Load in real data +// +//} + + +void TNeighborPixels::init_covariance( + double scale, + double d_soft, + double gamma_soft) +{ + // For each distance, initializes the covariance matrix + // describing the correlations between neighboring pixels. + // + // Input: + // scale: Correlation scale, in pc. + + // Calculate the distances + //std::cerr << "Calculating distances ..." << std::endl; + + std::vector dist; // In pc + double dmu = (dm_max - dm_min) / (double)(n_dists); + double mu; // Distance modulus, in mag + //std::cerr << "dm in (" << dm_min << ", " << dm_max << ")" + // << std::endl; + for(int i=0; i kernel + = [d_soft, gamma_soft, scale_coeff](double d2) -> double + { + if(d2 > 1.e-8) { + double d_eff = std::pow(d2, gamma_soft/2.); + d_eff += std::pow(d_soft, gamma_soft); + d_eff = std::pow(d_eff, 1./gamma_soft); + //std::cerr << "d: " << std::sqrt(d2) << " -> " << d_eff + // << std::endl; + return std::exp(scale_coeff * d_eff); + } else { + return 1.; + } + //double xi = scale_coeff * std::sqrt(d2); + //return 1. / (std::exp(xi) + std::exp(-xi)); + //return std::exp(scale_coeff * std::sqrt(d2)); + }; + + //std::cerr << "Initializing covariance matrices ..." << std::endl; + + inv_cov.clear(); + inv_cov_lonlat(lon, lat, dist, kernel, inv_cov); + + // TODO: Calculate A_cond for central and each neighbor, + // or for i and \i. + //conditional_gaussian_scalar( + // SharedMatrixXd& C_inv, 0, + // inv_var, SharedMatrixXd& A_cond); + + //std::cerr << "Reading off inverse variances ..." << std::endl; + + inv_var.clear(); + inv_var.reserve(n_pix*n_dists); + for(int pix=0; pix delta_max) { + dist_max = dist; + delta_max = delta_tmp; + } + } + dominant_dist.push_back(dist_max); + n_dominant_dist_samples.at(n_dists*pix + dist_max)++; + } + } + + if(verbosity >= 2) { + std::cerr << std::endl + << "Dominant distance histograms:" + << std::endl << std::endl; + + int h_max = 20; + for(int pix=0; pix h_max) { h = h_max; } + + int base = (h_max-1)*(n_dists+1) + dist; + + for(int j=0; j& sample) const +{ + // Calculates the mean of the specified pixel, given that + // the specified samples are chosen for the other pixels. + // + // Inputs: + // pix: index of pixel to compute mean for + // dist: distance bin to compute mean for + // sample: Which sample to choose for each pixel. Should + // have the same length as the total number of + // pixels. The pixel corresponding to `pix` will + // be ignored. + + //std::cerr << "(pix, dist) = (" << pix << ", " << dist << ")" << std::endl; + //std::cerr << "inv_cov[dist].shape = (" << inv_cov[dist]->rows() + // << ", " << inv_cov[dist]->cols() << ")" << std::endl; + + //std::cerr << "Calculating mean of (pix, dist) = (" + // << pix << ", " << dist << ")" << std::endl; + + double mu = 0.; + for(int i=0; i mu = " << mu << std::endl; + + return mu; +} + + +double TNeighborPixels::calc_mean_shifted( + unsigned int pix, + unsigned int dist, + const std::vector& sample, + const double shift_weight, + unsigned int start_pix) const +{ + // Calculates the mean of the specified pixel, given that + // the specified samples are chosen for the other pixels. + // + // An additional "shift" term is added into the inverse covariance + // matrix, which couples a given distance of the central pixel + // with the neighboring distances of the neighboring pixels. + // Neighboring distances of the central pixel are not coupled. + // This shift term deforms the prior, encouraging transitions between + // states in which a reddening jump occurs in neighboring distances. + // Taking to zero recovers the unmodified prior. + // + // Inputs: + // pix: index of pixel to compute mean for + // dist: distance bin to compute mean for + // sample: Which sample to choose for each pixel. Should + // have the same length as the total number of + // pixels. The pixel corresponding to `pix` will + // be ignored. + // shift_weight: A small positive constant (<< 1) which + // parameterizes the strength of the coupling + // between neighboring distances. + + double mu = 0.; + + Eigen::MatrixXd& inv_cov_0 = *(inv_cov[dist]); + + double norm = 1. + 2.*shift_weight; + + if(dist == 0) { + Eigen::MatrixXd& inv_cov_p1 = *(inv_cov[dist+1]); + //norm = 1. + shift_weight; + for(int i=start_pix; i& sample) const +{ + double p = 0.; + unsigned int s0, s1; + + for(int pix0=0; pix0& sample, + const double shift_weight, + const bool add_eff_prior) const +{ + double p = 0.; + unsigned int s0, s1; + + // Normalization factors related to distance shift. + // The factors of 2 out front come from the fact that we are + // only calculating one triangle of the pixel-pixel covariance matrix. + double norm = 1. + 2.*shift_weight; + double a = 2. / norm; // d,d + double b = 2. * shift_weight / norm; // d,d-1 or d-1,d + + for(int pix0=0; pix0 +#include +#include +#include +#include +#include + +#include "gaussian_process.h" +#include "healpix_tree.h" +#include "h5utils.h" + + +class TNeighborPixels { + // Information on a set of nearby pixels +private: + unsigned int n_pix, n_samples, n_dists; + double dm_min, dm_max; + + // shape = (pix, sample, dist) + std::vector delta; + std::vector log_dy; + + // shape = (pix, sample). Summed over distance. + std::vector sum_log_dy; + + // Prior and likelihood stored for each neighbor + std::vector prior; + std::vector likelihood; + + // Locations of neibhoring pixels + std::vector lon, lat; + std::vector nside, pix_idx; // Pairs of (nside, pix_idx) + + // Inverse covariance matrix for each distance + std::vector inv_cov; + + std::vector A_i_given_noti; + std::vector inv_var; // shape = (pix, dist) + + // Dominant distance for each (pix, sample) + std::vector dominant_dist; + + // # of samples in given pix with dominant distance at given dist + std::vector n_dominant_dist_samples; // shape = (pix, dist) + + // True if data loaded successfully, else false + bool loaded; + +public: + // Constructor/destructor + TNeighborPixels(uint32_t nside_center, + uint32_t pix_idx_center, + const std::string& neighbor_lookup_fname, + const std::string& pixel_lookup_fname, + const std::string& output_fname_pattern, + int n_samples_max=-1); + ~TNeighborPixels(); + + // Getters + double get_delta( + unsigned int pix, + unsigned int sample, + unsigned int dist) const; + + double get_log_dy( + unsigned int pix, + unsigned int sample, + unsigned int dist) const; + + double get_sum_log_dy( + unsigned int pix, + unsigned int sample) const; + + uint16_t get_dominant_dist( + unsigned int pix, + unsigned int sample) const; + + uint16_t get_n_dominant_dist_samples( + unsigned int pix, + unsigned int dist) const; + + const std::vector get_prior() const; + double get_prior(unsigned int pix, + unsigned int sample) const; + double get_likelihood(unsigned int pix, + unsigned int sample) const; + + unsigned int get_n_pix() const; + unsigned int get_n_samples() const; + unsigned int get_n_dists() const; + + double get_inv_cov( + unsigned int dist, + unsigned int pix0, + unsigned int pix1) const; + + bool data_loaded() const; + + // Setters + void set_delta( + double value, + unsigned int pix, + unsigned int sample, + unsigned int dist); + + void set_log_dy( + double value, + unsigned int pix, + unsigned int sample, + unsigned int dist); + + void set_sum_log_dy( + double value, + unsigned int pix, + unsigned int sample); + + // Calculate statistics + double get_inv_var(unsigned int pix, + unsigned int dist) const; + + double calc_mean( + unsigned int pix, + unsigned int dist, + const std::vector& sample) const; + + double calc_mean_shifted( + unsigned int pix, + unsigned int dist, + const std::vector& sample, + const double shift_weight, + unsigned int start_pix=0) const; + + double calc_lnprob(const std::vector& sample) const; + + double calc_lnprob_shifted( + const std::vector& sample, + const double shift_weight, + const bool add_eff_prior=true) const; + + // Initialization + bool load_neighbor_list( + uint32_t nside_center, uint32_t pix_idx_center, + const std::string& neighbor_lookup_fname); + + bool lookup_pixel_files( + const std::string& pixel_lookup_fname, + std::vector& file_idx); + + bool load_neighbor_los( + const std::string& output_fname_pattern, + const std::vector& file_idx, + int n_samples_max); + + void apply_priors( + const std::vector& mu, + const std::vector& sigma, + double reddening_scale); + + void apply_priors( + const std::vector& mu, + double sigma, + double reddening_scale); + + void apply_priors_indiv( + const std::vector& mu, + const std::vector& sigma, + double reddening_scale, + int pix, + int sample); + + void apply_priors_inner( + int pix, int sample, int dist, + double mu, double sigma, + double log_scale); + + void init_covariance( + double scale, + double d_soft, + double gamma_soft); + + void init_dominant_dist(int verbosity=0); +}; + + +#endif // _NEIGHBOR_PIXELS_H__ diff --git a/src/program_opts.cpp b/src/program_opts.cpp new file mode 100644 index 0000000..6eba83e --- /dev/null +++ b/src/program_opts.cpp @@ -0,0 +1,649 @@ + +#include "program_opts.h" + + +template +string to_string(const T& x) { + stringstream ss; + ss << x; + return ss.str(); +} + + +TProgramOpts::TProgramOpts() { + input_fname = "NONE"; + output_fname = "NONE"; + + save_surfs = false; + save_gridstars = false; + load_surfs = false; + + err_floor = 20; + + synthetic = false; + sample_stars = false; + star_steps = 1000; + star_samplers = 5; + star_p_replacement = 0.2; + min_EBV = 0.; + star_priors = true; + use_gaia = false; + + sigma_RV = -1.; + mean_RV = 3.1; + + //smoothing_slope = 0.05; + smoothing_alpha_coeff[0] = 0.880; + smoothing_alpha_coeff[1] = -2.963; + smoothing_beta_coeff[0] = 0.578; + smoothing_beta_coeff[1] = -1.879; + pct_smoothing_min = 0.; + pct_smoothing_max = -1.; + + discrete_los = false; + discrete_steps = 10000; + + N_regions = 30; + los_steps = 4000; + los_samplers = 2; + los_p_replacement = 0.0; + + N_clouds = 1; + cloud_steps = 2000; + cloud_samplers = 80; + cloud_p_replacement = 0.2; + + disk_prior = false; + log_Delta_EBV_floor = -10.; + log_Delta_EBV_ceil = -3.; + sigma_log_Delta_EBV = 0.75; + + SFD_prior = false; + SFD_subpixel = false; + subpixel_max = 1.e9; + ev_cut = 10.; + chi2_cut = 5.; + + N_runs = 4; + N_threads = 1; + + clobber = false; + + test_mode = false; + + verbosity = 0; + + LF_fname = DATADIR "PSMrLF.dat"; + template_fname = DATADIR "PS1_2MASS_colors.dat"; + ext_model_fname = DATADIR "PS1_2MASS_Extinction.dat"; + + neighbor_lookup_fname = "NONE"; + pixel_lookup_fname = "NONE"; + output_fname_pattern = "NONE"; + + correlation_scale = 1.0; // in pc + d_soft = 0.25; // in pc + gamma_soft = 4.0; // unitless +} + + +int get_program_opts(int argc, char **argv, TProgramOpts &opts) { + namespace po = boost::program_options; + + std::string config_fname = "NONE"; + + po::options_description config_desc("Configuration-file options"); + config_desc.add_options() + ("err-floor", + po::value(&(opts.err_floor)), + ("Error to add in quadrature (in millimags) (default: " + + to_string(opts.err_floor) + ")").c_str()) + + ("synthetic", + "Use synthetic photometric library " + "(default: use empirical library)") + ("sample-stars", + "Use MCMC to calculate individual stellar posteriors, " + "rather than approximate grid evaluation.") + ("star-steps", + po::value(&(opts.star_steps)), + ("# of MCMC steps per star (per sampler) (default: " + + to_string(opts.star_steps) + ")").c_str()) + ("star-samplers", + po::value(&(opts.star_samplers)), + ("# of samplers per dimension (stellar fit) (default: " + + to_string(opts.star_samplers) + ")").c_str()) + ("star-p-replacement", + po::value(&(opts.star_p_replacement)), + ("Probability of taking replacement step (stellar fit) " + "(default: " + + to_string(opts.star_p_replacement) + ")").c_str()) + ("no-stellar-priors", + "Turn off priors for individual stars.") + ("use-gaia", + "Use gaia parallax likelihood for individual stars.") + ("min-EBV", + po::value(&(opts.min_EBV)), + ("Minimum stellar E(B-V) (default: " + + to_string(opts.min_EBV) + ")").c_str()) + + ("mean-RV", + po::value(&(opts.mean_RV)), + ("Mean R_V (per star) (default: " + + to_string(opts.mean_RV) + ")").c_str()) + ("sigma-RV", + po::value(&(opts.sigma_RV)), + ("Variation in R_V (per star) (default: " + + to_string(opts.sigma_RV) + + ", interpreted as no variance)").c_str()) + + // ("smoothing-pct", + // po::value(&(opts.smoothing_slope)), + // ("Degree of smoothing (sigma/EBV) of per-star " + // "surfaces (default: " + + // to_string(opts.smoothing_slope) + ")").c_str()) + ("pct-smoothing-coeffs", + po::value< vector >()->multitoken(), + ("Coefficients for alpha and beta smoothing parameters " + "(default: " + + to_string(opts.smoothing_alpha_coeff[0]) + " " + + to_string(opts.smoothing_alpha_coeff[1]) + " " + + to_string(opts.smoothing_beta_coeff[0]) + " " + + to_string(opts.smoothing_beta_coeff[1]) + ")").c_str()) + ("pct-smoothing-min", + po::value(&(opts.pct_smoothing_min)), + ("Minimum smoothing percent of per-star surfaces " + "(default: " + + to_string(opts.pct_smoothing_min) + ")").c_str()) + ("pct-smoothing-max", + po::value(&(opts.pct_smoothing_max)), + ("Maximum smoothing percent of per-star surfaces (default: " + + to_string(opts.pct_smoothing_max) + ")").c_str()) + + ("discrete-los", + "Use the discrete line-of-sight model.") + ("discrete-steps", + po::value(&(opts.discrete_steps)), + ("# of steps to take for the discrete l.o.s. sampler " + "(default: " + + to_string(opts.discrete_steps) + ")").c_str()) + + ("regions", + po::value(&(opts.N_regions)), + ("# of piecewise-linear regions in l.o.s. extinction profile " + "(default: " + + to_string(opts.N_regions) + ")").c_str()) + ("los-steps", + po::value(&(opts.los_steps)), + ("# of MCMC steps in l.o.s. fit (per sampler) (default: " + + to_string(opts.los_steps) + ")").c_str()) + ("los-samplers", + po::value(&(opts.los_samplers)), + ("# of samplers per dimension (l.o.s. fit) (default: " + + to_string(opts.los_samplers) + ")").c_str()) + ("los-p-replacement", + po::value(&(opts.los_p_replacement)), + ("Probability of taking replacement step (l.o.s. fit) " + "(default: " + + to_string(opts.los_p_replacement) + ")").c_str()) + + ("clouds", + po::value(&(opts.N_clouds)), + ("# of clouds along the line of sight (default: " + + to_string(opts.N_clouds) + ")\n" + "Setting this option causes the sampler to " + "also fit a discrete cloud model of " + "the l.o.s. extinction profile.").c_str()) + ("cloud-steps", + po::value(&(opts.cloud_steps)), + ("# of MCMC steps in cloud fit (per sampler) (default: " + + to_string(opts.cloud_steps) + ")").c_str()) + ("cloud-samplers", + po::value(&(opts.cloud_samplers)), + ("# of samplers per dimension (cloud fit) (default: " + + to_string(opts.cloud_samplers) + ")").c_str()) + ("cloud-p-replacement", + po::value(&(opts.cloud_p_replacement)), + ("Probability of taking replacement step (cloud fit) " + "(default: " + + to_string(opts.cloud_p_replacement) + ")").c_str()) + + ("disk-prior", + "Assume that dust density roughly traces " + "stellar disk density.") + ("log-Delta-EBV-min", + po::value(&(opts.log_Delta_EBV_floor)), + ("Minimum log(Delta EBV) in l.o.s. reddening prior " + "(default: " + + to_string(opts.log_Delta_EBV_floor) + ")").c_str()) + ("log-Delta-EBV-max", + po::value(&(opts.log_Delta_EBV_ceil)), + ("Maximum log(Delta EBV) in l.o.s. reddening prior " + "(default: " + + to_string(opts.log_Delta_EBV_ceil) + ")").c_str()) + ("sigma-log-Delta-EBV", + po::value(&(opts.sigma_log_Delta_EBV)), + ("Std. dev. of log(Delta EBV) in one distance bin " + "in l.o.s. reddening prior (default: " + + to_string(opts.sigma_log_Delta_EBV) + ")").c_str()) + ("SFD-prior", + "Use SFD E(B-V) as a prior on the total " + "extinction in each pixel.") + ("SFD-subpixel", + "Use SFD E(B-V) as a subpixel template for the " + "angular variation in reddening.") + ("subpixel-max", + po::value(&(opts.subpixel_max)), + ("Maximum subpixel value (above this values, stars will " + "be filtered out). (default: " + + to_string(opts.subpixel_max) + ")").c_str()) + ("evidence-cut", + po::value(&(opts.ev_cut)), + ("Delta lnZ to use as threshold for including star " + "in l.o.s. fit. Used with MCMC sampling. " + "(default: " + + to_string(opts.ev_cut) + ")").c_str()) + ("chi2-cut", + po::value(&(opts.chi2_cut)), + ("chi^2 / passband to use as threshold for " + "including star in l.o.s. fit.\n" + "Used with grid evaluation. (default: " + + to_string(opts.chi2_cut) + ")").c_str()) + ("runs", + po::value(&(opts.N_runs)), + ("# of times to run each chain (to check\n" + "for non-convergence) (default: " + + to_string(opts.N_runs) + ")").c_str()) + + ("LF-file", + po::value(&(opts.LF_fname)), + "File containing stellar luminosity function.") + ("template-file", + po::value(&(opts.template_fname)), + "File containing stellar color templates.") + ("ext-file", + po::value(&(opts.ext_model_fname)), + "File containing extinction coefficients.") + + ("neighbor-lookup-file", + po::value(&(opts.neighbor_lookup_fname)), + "Lookup file that maps pixels -> neighboring pixels.") + ("pixel-lookup-file", + po::value(&(opts.pixel_lookup_fname)), + "Lookup file that maps pixels -> files.") + ("output-fname-pattern", + po::value(&(opts.output_fname_pattern)), + ("Filename pattern for previous iteration of \n" + "output files. E.g., output.@@@@@.h5.")) + + ("correlation-scale", + po::value(&(opts.correlation_scale)), + ("Dust log density correlation scale, in pc " + "(default: " + + to_string(opts.correlation_scale) + ")").c_str()) + ("corr-softening-scale", + po::value(&(opts.d_soft)), + ("Softening length for the dust log density " + "correlation scale, in pc (default: " + + to_string(opts.d_soft) + ")").c_str()) + ("corr-softening-gamma", + po::value(&(opts.gamma_soft)), + ("Shape of the correlation softening. Higher -> sharper " + "(default: " + + to_string(opts.d_soft) + ")").c_str()) + ; + + po::options_description dsc_samp_settings_desc( + "Settings for discrete l.o.s. model sampler."); + dsc_samp_settings_desc.add_options() + ("dsc-n-temperatures", + po::value(&(opts.dsc_samp_settings.n_temperatures)), + ("# of temperatures to use when sampling discrete \n" + "l.o.s. model (default: " + + to_string(opts.dsc_samp_settings.n_temperatures) + + ")").c_str()) + ("dsc-beta-spacing", + po::value(&(opts.dsc_samp_settings.beta_spacing)), + ("Spacing of temperature ladder for discrete l.o.s. \n" + "(1=degenerate, 0=maximal spacing). (default: " + + to_string(opts.dsc_samp_settings.beta_spacing) + + ")").c_str()) + ("dsc-central-steps-per-update", + po::value(&(opts.dsc_samp_settings.central_steps_per_update)), + ("Discrete l.o.s. sampler: # of steps to take in central \n" + "pixel per distance per update. (default: " + + to_string(opts.dsc_samp_settings.central_steps_per_update) + + ")").c_str()) + ("dsc-neighbor-steps-per-update", + po::value(&(opts.dsc_samp_settings.neighbor_steps_per_update)), + ("Discrete l.o.s. sampler: # of steps to take in each \n" + "neighboring pixel per update. (default: " + + to_string(opts.dsc_samp_settings.neighbor_steps_per_update) + + ")").c_str()) + ("dsc-updates-per-swap", + po::value(&(opts.dsc_samp_settings.updates_per_swap)), + ("Discrete l.o.s. sampler: # of update rounds of pixels \n" + "per attemped swap between temperatures (default: " + + to_string(opts.dsc_samp_settings.updates_per_swap) + + ")").c_str()) + ("dsc-n-swaps", + po::value(&(opts.dsc_samp_settings.n_swaps)), + ("Discrete l.o.s. sampler: total # of swaps between \n" + "temperatures to attempt (default: " + + to_string(opts.dsc_samp_settings.n_swaps) + + ")").c_str()) + ("dsc-burnin-fraction", + po::value(&(opts.dsc_samp_settings.burnin_frac)), + ("Discrete l.o.s. sampler: Length of burn-in, as a \n" + "fraction of the main sampling phase (default: " + + to_string(opts.dsc_samp_settings.burnin_frac) + + ")").c_str()) + ("dsc-n-save", + po::value(&(opts.dsc_samp_settings.n_save)), + ("Discrete l.o.s. sampler: # of samples to save \n" + "(default: " + + to_string(opts.dsc_samp_settings.n_save) + + ")").c_str()) + ("dsc-log-shift-weight-min", + po::value(&(opts.dsc_samp_settings.log_shift_weight_min)), + ("Discrete l.o.s. sampler: Parameter that controls \n" + "strength of correlations between neighboring \n" + "distances in the temperature=1 sampler, \n" + "as a fraction of inv. cov. between neighboring \n" + "pixels (default: " + + to_string(opts.dsc_samp_settings.log_shift_weight_min) + + ")").c_str()) + ("dsc-log-shift-weight-max", + po::value(&(opts.dsc_samp_settings.log_shift_weight_max)), + ("Discrete l.o.s. sampler: Parameter that controls \n" + "strength of correlations between neighboring \n" + "distances in the highest-temperature sampler, \n" + "as a fraction of inv. cov. between neighboring \n" + "pixels (default: " + + to_string(opts.dsc_samp_settings.log_shift_weight_max) + + ")").c_str()) + ("dsc-shift-weight-ladder-logarithmic", + po::value(&(opts.dsc_samp_settings.shift_weight_ladder_logarithmic)), + ("If this flag is set, then the shift weights will \n" + "be spaced logarithmically, instead of linearly \n" + "(default: " + + to_string(opts.dsc_samp_settings.shift_weight_ladder_logarithmic) + + ")").c_str()) + ("dsc-save-all-temperatures", + po::value(&(opts.dsc_samp_settings.save_all_temperatures)), + ("Discrete l.o.s. sampler: If true, samples from higher \n" + "temperature samplers will be saved as well (default: " + + to_string(opts.dsc_samp_settings.save_all_temperatures) + + ")").c_str()) + ("dsc-p-badstar", + po::value(&(opts.dsc_samp_settings.p_badstar)), + ("Stellar outlier fraction: larger values mean less \n" + "weight to outliers (default: " + + to_string(opts.dsc_samp_settings.p_badstar) + + ")").c_str()) + ; + config_desc.add(dsc_samp_settings_desc); + + po::options_description gal_desc( + "Galactic Structural Parameters (all distances in pc)"); + gal_desc.add_options() + ("R0", + po::value(&(opts.gal_struct_params.R0)), + ("Solar Galactocentric distance (default: " + + to_string(opts.gal_struct_params.R0) + ")").c_str()) + ("Z0", + po::value(&(opts.gal_struct_params.Z0)), + ("Solar height above Galactic midplane (default: " + + to_string(opts.gal_struct_params.Z0) + ")").c_str()) + + ("H_thin", + po::value(&(opts.gal_struct_params.H1)), + ("Thin-disk scale height (default: " + + to_string(opts.gal_struct_params.H1) + ")").c_str()) + ("L_thin", + po::value(&(opts.gal_struct_params.L1)), + ("Thin-disk scale length (default: " + + to_string(opts.gal_struct_params.L1) + ")").c_str()) + + ("f_thick", + po::value(&(opts.gal_struct_params.f_thick)), + ("Thick-disk fraction, defined locally (default: " + + to_string(opts.gal_struct_params.f_thick) + + ")").c_str()) + ("H_thick", + po::value(&(opts.gal_struct_params.H2)), + ("Thick-disk scale height (default: " + + to_string(opts.gal_struct_params.H2) + ")").c_str()) + ("L_thick", + po::value(&(opts.gal_struct_params.L2)), + ("Thin-disk scale length (default: " + + to_string(opts.gal_struct_params.L2) + ")").c_str()) + + ("L_epsilon", + po::value(&(opts.gal_struct_params.L_epsilon)), + ("Disk softening scale (default: " + + to_string(opts.gal_struct_params.L_epsilon) + + ")").c_str()) + + ("f_halo", + po::value(&(opts.gal_struct_params.fh)), + ("Halo fraction, defined locally (default: " + + to_string(opts.gal_struct_params.fh) + ")").c_str()) + ("q_halo", + po::value(&(opts.gal_struct_params.qh)), + ("Halo flattening parameter (default: " + + to_string(opts.gal_struct_params.qh) + ")").c_str()) + ("n_halo", + po::value(&(opts.gal_struct_params.nh)), + ("Halo density slope (default: " + + to_string(opts.gal_struct_params.nh) + ")").c_str()) + ("R_break", + po::value(&(opts.gal_struct_params.R_br)), + ("Halo break radius (default: " + + to_string(opts.gal_struct_params.R_br) + + ")").c_str()) + ("n_halo_outer", + po::value(&(opts.gal_struct_params.nh_outer)), + ("Halo outer density slope, past break (default: " + + to_string(opts.gal_struct_params.nh_outer) + + ")").c_str()) + + ("H_ISM", + po::value(&(opts.gal_struct_params.H_ISM)), + ("Dust scale height (default: " + + to_string(opts.gal_struct_params.H_ISM) + + ")").c_str()) + ("L_ISM", + po::value(&(opts.gal_struct_params.L_ISM)), + ("Dust scale length (default: " + + to_string(opts.gal_struct_params.L_ISM) + + ")").c_str()) + ("dH_dR_ISM", + po::value(&(opts.gal_struct_params.dH_dR_ISM)), + ("Dust flare slope (default: " + + to_string(opts.gal_struct_params.dH_dR_ISM) + + ")").c_str()) + ("R_flair_ISM", + po::value(&(opts.gal_struct_params.R_flair_ISM)), + ("Dust flair slope (default: " + + to_string(opts.gal_struct_params.R_flair_ISM) + + ")").c_str()) + + ("mu_FeH_inf", + po::value(&(opts.gal_struct_params.mu_FeH_inf)), + ("Disk metallicity at large elevation above " + "midplane (default: " + + to_string(opts.gal_struct_params.mu_FeH_inf) + + ")").c_str()) + ("delta_mu_FeH", + po::value(&(opts.gal_struct_params.delta_mu_FeH)), + ("Disk metallicity at midplane, minus metallicity " + "at large elevation (default: " + + to_string(opts.gal_struct_params.delta_mu_FeH) + + ")").c_str()) + ("H_mu_FeH", + po::value(&(opts.gal_struct_params.H_mu_FeH)), + ("Disk metallicity scale height (default: " + + to_string(opts.gal_struct_params.H_mu_FeH) + + ")").c_str()) + ; + config_desc.add(gal_desc); + + po::options_description generic_desc( + std::string("Usage: ") + argv[0] + + " [Input filename] [Output filename] \n\n" + "Commandline Options"); + generic_desc.add_options() + ("help", "Display this help message") + ("show-config", "Display configuration-file options") + ("version", "Display version number") + + ("input", + po::value(&(opts.input_fname)), + "Input HDF5 filename (contains stellar photometry)") + ("output", + po::value(&(opts.output_fname)), + "Output HDF5 filename (MCMC output and smoothed " + "probability surfaces)") + + ("config", + po::value(&config_fname), + "Configuration file containing additional options.") + + ("test-los", + "Allow user to test specific line-of-sight profiles manually.") + ; + + po::options_description dual_desc( + "Dual Options (both commandline and configuration file)"); + dual_desc.add_options() + ("save-surfs", "Save probability surfaces.") + ("load-surfs", "Use pre-computed probability surfaces from output file.") + ("save-gridstars", "Save grid-evaluated stellar inferences.") + ("clobber", "Overwrite existing output. Otherwise, will\n" + "only process pixels with incomplete output.") + ("verbosity", + po::value(&(opts.verbosity)), + ("Level of verbosity (0 = minimal, 2 = highest) (default: " + + to_string(opts.verbosity) + ")").c_str()) + ("threads", + po::value(&(opts.N_threads)), + ("# of threads to run on (default: " + + to_string(opts.N_threads) + ")").c_str()) + ("force-pix", + po::value>()->multitoken(), + ("Force the given pixels to run. E.g., \"1024-0 512-50\\n " + "would force (nside,healpix_idx) = (1024,0) and (512,50)\n " + "to run, even if they are already present in the output.")) + ; + + po::positional_options_description pd; + pd.add("input", 1).add("output", 1); + + + // Agglomerate different categories of options + po::options_description cmdline_desc; + cmdline_desc.add(generic_desc).add(dual_desc); + + po::options_description config_all_desc; + config_all_desc.add(config_desc).add(dual_desc); + + + // Parse options + + po::variables_map vm; + po::store( + po::command_line_parser(argc, argv).options(cmdline_desc) + .positional(pd).run(), + vm + ); + po::notify(vm); + + if(config_fname != "NONE") { + std::ifstream f_config(config_fname.c_str()); + if(!f_config) { + cerr << "Could not open " << config_fname << endl; + cerr << "Quitting." << endl; + return -1; + } + po::store(po::parse_config_file(f_config, config_all_desc, false), vm); + f_config.close(); + + po::notify(vm); + } + + if(vm.count("help")) { + cout << cmdline_desc << endl; + return 0; + } + + if(vm.count("show-config")) { + cout << config_all_desc << endl; + return 0; + } + + if(vm.count("version")) { + cout << "git commit " << GIT_BUILD_VERSION << endl; + return 0; + } + + if(vm.count("synthetic")) { opts.synthetic = true; } + if(vm.count("sample-stars")) { opts.sample_stars = true; } + if(vm.count("save-surfs")) { opts.save_surfs = true; } + if(vm.count("load-surfs")) { opts.load_surfs = true; } + if(vm.count("save-gridstars")) { opts.save_gridstars = true; } + if(vm.count("no-stellar-priors")) { opts.star_priors = false; } + if(vm.count("use-gaia")) { opts.use_gaia = true; } + if(vm.count("disk-prior")) { opts.disk_prior = true; } + if(vm.count("SFD-prior")) { opts.SFD_prior = true; } + if(vm.count("SFD-subpixel")) { opts.SFD_subpixel = true; } + if(vm.count("clobber")) { opts.clobber = true; } + if(vm.count("test-los")) { opts.test_mode = true; } + if(vm.count("discrete-los")) { opts.discrete_los = true; } + + // Read percent smoothing coefficients + if(!vm["pct-smoothing-coeffs"].empty()) { + vector pct_smoothing_coeffs = + vm["pct-smoothing-coeffs"].as >(); + + if(pct_smoothing_coeffs.size() != 4) { + cerr << "'pct-smoothing-coeffs' takes exactly 4 numbers." << endl; + return -1; + } + + opts.smoothing_alpha_coeff[0] = pct_smoothing_coeffs[0]; + opts.smoothing_alpha_coeff[1] = pct_smoothing_coeffs[1]; + opts.smoothing_beta_coeff[0] = pct_smoothing_coeffs[2]; + opts.smoothing_beta_coeff[1] = pct_smoothing_coeffs[3]; + } + + // Read forced pixels + if(!vm["force-pix"].empty()) { + opts.force_pix = + vm["force-pix"].as >(); + } + + // Convert error floor from mmags to mags + opts.err_floor /= 1000.; + + if(opts.input_fname == "NONE") { + cerr << "Input filename required." << endl << endl; + cerr << cmdline_desc << endl; + return -1; + } + if(opts.output_fname == "NONE") { + cerr << "Output filename required." << endl << endl; + cerr << cmdline_desc << endl; + return -1; + } + + if(opts.N_regions != 0) { + if(120 % (opts.N_regions) != 0) { + cerr << "# of regions in extinction profile must divide " + "120 without remainder." << endl; + return -1; + } + } + + return 1; +} diff --git a/src/program_opts.h b/src/program_opts.h new file mode 100644 index 0000000..9dbd48f --- /dev/null +++ b/src/program_opts.h @@ -0,0 +1,106 @@ +#ifndef _PROGRAM_OPTS_H__ +#define _PROGRAM_OPTS_H__ + + +#include +#include +#include +#include + +#include + +#include "model.h" +#include "bayestar_config.h" +#include "los_sampler.h" + + +using namespace std; + + +struct TProgramOpts { + string input_fname; + string output_fname; + + bool save_surfs; + bool save_gridstars; + bool load_surfs; + + double err_floor; // in millimags + + bool synthetic; + bool sample_stars; + unsigned int star_steps; + unsigned int star_samplers; + double star_p_replacement; + double min_EBV; // in mags + bool star_priors; + bool use_gaia; + + double sigma_RV; + double mean_RV; + + //double smoothing_slope; + double smoothing_alpha_coeff[2]; + double smoothing_beta_coeff[2]; + double pct_smoothing_min; + double pct_smoothing_max; + + bool discrete_los; + unsigned int discrete_steps; + + unsigned int N_regions; + unsigned int los_steps; + unsigned int los_samplers; + double los_p_replacement; + + unsigned int N_clouds; + unsigned int cloud_steps; + unsigned int cloud_samplers; + double cloud_p_replacement; + + bool disk_prior; + double log_Delta_EBV_floor; + double log_Delta_EBV_ceil; + double sigma_log_Delta_EBV; + + bool SFD_prior; + bool SFD_subpixel; + double subpixel_max; + double ev_cut; + double chi2_cut; + + unsigned int N_runs; + unsigned int N_threads; + + bool clobber; + + bool test_mode; + + int verbosity; + + string LF_fname; + string template_fname; + string ext_model_fname; + + TGalStructParams gal_struct_params; + + string neighbor_lookup_fname; + string pixel_lookup_fname; + string output_fname_pattern; + + double correlation_scale; + double d_soft; + double gamma_soft; + + TDiscreteLOSSamplingSettings dsc_samp_settings; + + std::vector force_pix; + + TProgramOpts(); +}; + + +int get_program_opts(int argc, char **argv, TProgramOpts &opts); + + +#endif // _PROGRAM_OPTS_H__ diff --git a/src/sampler.cpp b/src/sampler.cpp index 7d09cf4..7a95867 100644 --- a/src/sampler.cpp +++ b/src/sampler.cpp @@ -1,36 +1,37 @@ /* * sampler.cpp - * + * * Samples from posterior distribution of line-of-sight model. - * + * * This file is part of bayestar. * Copyright 2012 Gregory Green - * + * * Bayestar is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. - * + * */ + #include "sampler.h" /**************************************************************************************************************************** - * + * * TMCMCParams - * + * ****************************************************************************************************************************/ TMCMCParams::TMCMCParams(TGalacticLOSModel *_gal_model, TSyntheticStellarModel *_synth_stellar_model, TStellarModel *_emp_stellar_model, @@ -38,48 +39,48 @@ TMCMCParams::TMCMCParams(TGalacticLOSModel *_gal_model, TSyntheticStellarModel * : gal_model(_gal_model), synth_stellar_model(_synth_stellar_model), emp_stellar_model(_emp_stellar_model), ext_model(_ext_model), data(_data), N_DM(_N_DM), DM_min(_DM_min), DM_max(_DM_max) { - N_stars = data->star.size(); - EBV_interp = new TLinearInterp(DM_min, DM_max, N_DM); - - // Defaults - lnp0 = -10.; - idx_star = 0; - - EBV_floor = 0.; - - vary_RV = false; - RV_mean = 3.1; - RV_variance = 0.2*0.2; - - use_priors = true; + N_stars = data->star.size(); + EBV_interp = new TLinearInterp(DM_min, DM_max, N_DM); + + // Defaults + lnp0 = -10.; + idx_star = 0; + + EBV_floor = 0.; + + vary_RV = false; + RV_mean = 3.1; + RV_variance = 0.2*0.2; + + use_priors = true; } TMCMCParams::~TMCMCParams() { - delete EBV_interp; + delete EBV_interp; } void TMCMCParams::update_EBV_interp(const double *x) { - double EBV = 0.; - for(unsigned int i=0; i= DM_max) { return EBV_max; } - return (*EBV_interp)(DM); + if(DM <= DM_min) { return EBV_min; } else if(DM >= DM_max) { return EBV_max; } + return (*EBV_interp)(DM); } /**************************************************************************************************************************** - * + * * Probability density functions - * + * ****************************************************************************************************************************/ @@ -89,42 +90,42 @@ double TMCMCParams::get_EBV(double DM) { double logP_single_star_synth(const double *x, double EBV, double RV, const TGalacticLOSModel &gal_model, const TSyntheticStellarModel &stellar_model, TExtinctionModel &ext_model, const TStellarData::TMagnitudes &d, TSED *tmp_sed) { - double logP = 0.; - - /* - * Likelihood - */ - bool del_sed = false; - if(tmp_sed == NULL) { - del_sed = true; - tmp_sed = new TSED(true); - } - if(!stellar_model.get_sed(x+1, *tmp_sed)) { - if(del_sed) { delete tmp_sed; } - return neg_inf_replacement; - } - - double logL = 0.; - double tmp; - for(unsigned int i=0; iabsmag[i] + x[_DM] + EBV * ext_model.get_A(RV, i); // Model apparent magnitude - logL -= log( 1. + exp((tmp - d.maglimit[i] - 0.16) / 0.20) ); - //logL += log( 0.5 - 0.5 * erf((tmp - d.maglimit[i] + 0.1) / 0.25) ); // Completeness fraction - tmp = (d.m[i] - tmp) / d.err[i]; - logL -= 0.5*tmp*tmp; - } - } - logP += logL - d.lnL_norm; - - if(del_sed) { delete tmp_sed; } - - /* - * Priors - */ - logP += gal_model.log_prior_synth(x); - - return logP; + double logP = 0.; + + /* + * Likelihood + */ + bool del_sed = false; + if(tmp_sed == NULL) { + del_sed = true; + tmp_sed = new TSED(true); + } + if(!stellar_model.get_sed(x+1, *tmp_sed)) { + if(del_sed) { delete tmp_sed; } + return neg_inf_replacement; + } + + double logL = 0.; + double tmp; + for(unsigned int i=0; iabsmag[i] + x[_DM] + EBV * ext_model.get_A(RV, i); // Model apparent magnitude + logL -= log( 1. + exp((tmp - d.maglimit[i]) / d.maglim_width[i]) ); + //logL += log( 0.5 - 0.5 * erf((tmp - d.maglimit[i] + 0.1) / 0.25) ); // Completeness fraction + tmp = (d.m[i] - tmp) / d.err[i]; + logL -= 0.5*tmp*tmp; + } + } + logP += logL - d.lnL_norm; + + if(del_sed) { delete tmp_sed; } + + /* + * Priors + */ + logP += gal_model.log_prior_synth(x); + + return logP; } // Natural logarithm of posterior probability density for one star, given parameters x, where @@ -133,57 +134,57 @@ double logP_single_star_synth(const double *x, double EBV, double RV, double logP_single_star_emp(const double *x, double EBV, double RV, const TGalacticLOSModel &gal_model, const TStellarModel &stellar_model, TExtinctionModel &ext_model, const TStellarData::TMagnitudes &d, TSED *tmp_sed) { - double logP = 0.; - - /* - * Don't allow NaN parameters - */ - if(isnan(x[0]) || isnan(x[1]) || isnan(x[2])) { - #pragma omp critical (cout) - { - std::cerr << "Encountered NaN parameter value!" << std::endl; - std::cerr << " " << x[0] << std::endl; - std::cerr << " " << x[1] << std::endl; - std::cerr << " " << x[2] << std::endl; - } - return neg_inf_replacement; - } - - /* - * Likelihood - */ - bool del_sed = false; - if(tmp_sed == NULL) { - del_sed = true; - tmp_sed = new TSED(true); - } - if(!stellar_model.get_sed(x+1, *tmp_sed)) { - if(del_sed) { delete tmp_sed; } - return neg_inf_replacement; - } - - double logL = 0.; - double tmp; - for(unsigned int i=0; iabsmag[i] + x[_DM] + EBV * ext_model.get_A(RV, i); // Model apparent magnitude - logL -= log( 1. + exp((tmp - d.maglimit[i] - 0.16) / 0.20) ); - //logL += log( 0.5 - 0.5 * erf((tmp - d.maglimit[i] + 0.1) / 0.25) ); // Completeness fraction - //std::cout << tmp << ", " << d.maglimit[i] << std::endl; - tmp = (d.m[i] - tmp) / d.err[i]; - logL -= 0.5*tmp*tmp; - } - } - logP += logL - d.lnL_norm; - - if(del_sed) { delete tmp_sed; } - - /* - * Priors - */ - logP += gal_model.log_prior_emp(x) + stellar_model.get_log_lf(x[1]); - - return logP; + double logP = 0.; + + /* + * Don't allow NaN parameters + */ + if(std::isnan(x[0]) || std::isnan(x[1]) || std::isnan(x[2])) { + /*#pragma omp critical (cout) + { + std::cerr << "Encountered NaN parameter value!" << std::endl; + std::cerr << " " << x[0] << std::endl; + std::cerr << " " << x[1] << std::endl; + std::cerr << " " << x[2] << std::endl; + }*/ + return neg_inf_replacement; + } + + /* + * Likelihood + */ + bool del_sed = false; + if(tmp_sed == NULL) { + del_sed = true; + tmp_sed = new TSED(true); + } + if(!stellar_model.get_sed(x+1, *tmp_sed)) { + if(del_sed) { delete tmp_sed; } + return neg_inf_replacement; + } + + double logL = 0.; + double tmp; + for(unsigned int i=0; iabsmag[i] + x[_DM] + EBV * ext_model.get_A(RV, i); // Model apparent magnitude + logL -= log( 1. + exp((tmp - d.maglimit[i]) / d.maglim_width[i]) ); + //logL += log( 0.5 - 0.5 * erf((tmp - d.maglimit[i] + 0.1) / 0.25) ); // Completeness fraction + //std::cout << tmp << ", " << d.maglimit[i] << std::endl; + tmp = (d.m[i] - tmp) / d.err[i]; + logL -= 0.5*tmp*tmp; + } + } + logP += logL - d.lnL_norm; + + if(del_sed) { delete tmp_sed; } + + /* + * Priors + */ + logP += gal_model.log_prior_emp(x) + stellar_model.get_log_lf(x[1]); + + return logP; } @@ -193,1028 +194,1314 @@ double logP_single_star_emp(const double *x, double EBV, double RV, double logP_single_star_emp_noprior(const double *x, double EBV, double RV, const TGalacticLOSModel &gal_model, const TStellarModel &stellar_model, TExtinctionModel &ext_model, const TStellarData::TMagnitudes &d, TSED *tmp_sed) { - double logP = 0.; - - /* - * Likelihood - */ - bool del_sed = false; - if(tmp_sed == NULL) { - del_sed = true; - tmp_sed = new TSED(true); - } - if(!stellar_model.get_sed(x+1, *tmp_sed)) { - if(del_sed) { delete tmp_sed; } - return neg_inf_replacement; - } - - double logL = 0.; - double tmp; - for(unsigned int i=0; iabsmag[i] + x[_DM] + EBV * ext_model.get_A(RV, i); // Model apparent magnitude - tmp = (d.m[i] - tmp) / d.err[i]; - logL -= 0.5*tmp*tmp; - } - } - logP += logL - d.lnL_norm; - - if(del_sed) { delete tmp_sed; } - - return logP; + double logP = 0.; + + /* + * Likelihood + */ + bool del_sed = false; + if(tmp_sed == NULL) { + del_sed = true; + tmp_sed = new TSED(true); + } + if(!stellar_model.get_sed(x+1, *tmp_sed)) { + if(del_sed) { delete tmp_sed; } + return neg_inf_replacement; + } + + double logL = 0.; + double tmp; + for(unsigned int i=0; iabsmag[i] + x[_DM] + EBV * ext_model.get_A(RV, i); // Model apparent magnitude + tmp = (d.m[i] - tmp) / d.err[i]; + logL -= 0.5*tmp*tmp; + } + } + logP += logL - d.lnL_norm; + + if(del_sed) { delete tmp_sed; } + + return logP; } double logP_EBV(TMCMCParams &p) { - double logP = 0.; - - // SFD prior - logP -= (p.EBV_max * p.EBV_max) / (2. * p.EBV_SFD * p.EBV_SFD); - - // Lognormal - double tmp; - for(double DM = p.DM_min; DM <= p.DM_max; DM += (p.DM_max-p.DM_min)/10.) { - tmp = p.get_EBV(DM); - logP -= tmp*tmp / 2.; - } - - return logP; + double logP = 0.; + + // SFD prior + logP -= (p.EBV_max * p.EBV_max) / (2. * p.EBV_SFD * p.EBV_SFD); + + // Lognormal + double tmp; + for(double DM = p.DM_min; DM <= p.DM_max; DM += (p.DM_max-p.DM_min)/10.) { + tmp = p.get_EBV(DM); + logP -= tmp*tmp / 2.; + } + + return logP; } double logP_los_synth(const double *x, unsigned int N, TMCMCParams &p, double *lnP_star) { - double logP = 0.; - - // Prior on RV - double RV = x[0]; - if(p.ext_model->in_model(RV)) { - logP -= (RV - 3.1)*(RV - 3.1) / (2. * 0.1 * 0.1); - } else { - return neg_inf_replacement; - } - - // Prior on extinction - logP += logP_EBV(p); - - // Probabilities of stars - double tmp; - const double *x_star; - for(unsigned int i=0; istar[i]); - logP += tmp; - if(lnP_star != NULL) { lnP_star[i] = tmp; } - } - - return logP; + double logP = 0.; + + // Prior on RV + double RV = x[0]; + if(p.ext_model->in_model(RV)) { + logP -= (RV - 3.1)*(RV - 3.1) / (2. * 0.1 * 0.1); + } else { + return neg_inf_replacement; + } + + // Prior on extinction + logP += logP_EBV(p); + + // Probabilities of stars + double tmp; + const double *x_star; + for(unsigned int i=0; istar[i]); + logP += tmp; + if(lnP_star != NULL) { lnP_star[i] = tmp; } + } + + return logP; } /**************************************************************************************************************************** - * + * * Sampling functions - * + * ****************************************************************************************************************************/ void sample_model_synth(TGalacticLOSModel &galactic_model, TSyntheticStellarModel &stellar_model, TExtinctionModel &extinction_model, TStellarData &stellar_data) { - unsigned int N_DM = 20; - double DM_min = 4.; - double DM_max = 20.; - TMCMCParams params(&galactic_model, &stellar_model, NULL, &extinction_model, &stellar_data, N_DM, DM_min, DM_max); - TMCMCParams params_tmp(&galactic_model, &stellar_model, NULL, &extinction_model, &stellar_data, N_DM, DM_min, DM_max); - - // Random number generator - gsl_rng *r; - seed_gsl_rng(&r); - - // Vector describing position in probability space - size_t length = 1 + params.N_DM + 4*params.N_stars; - // x = {RV, Delta_EBV_1, ..., Delta_EBV_M, Theta_1, ..., Theta_N}, where Theta = {DM, logMass, logtau, FeH}. - double *x = new double[length]; - - // Random starting point for reddening profile - x[0] = 3.1;// + gsl_ran_gaussian_ziggurat(r, 0.2); // RV - for(size_t i=0; iEBV / (double)N_DM * gsl_ran_chisq(r, 1.); } // Delta_EBV - - // Random starting point for each star - TSED sed_tmp(true); - for(size_t i = 1 + params.N_DM; i < 1 + params.N_DM + 4*params.N_stars; i += 4) { - x[i] = 5. + 13.*gsl_rng_uniform(r); - double logMass, logtau, FeH, tau; - bool in_lib = false; - while(!in_lib) { - logMass = gsl_ran_gaussian_ziggurat(r, 0.5); - tau = -1.; - while(tau <= 0.) { - tau = 1.e9 * (5. + gsl_ran_gaussian_ziggurat(r, 2.)); - } - logtau = log10(tau); - FeH = -1.0 + gsl_ran_gaussian_ziggurat(r, 1.); - - in_lib = stellar_model.get_sed(logMass, logtau, FeH, sed_tmp); - } - x[i+1] = logMass; - x[i+2] = logtau; - x[i+3] = FeH; - } - - params.update_EBV_interp(x); - double *lnp_star = new double[params.N_stars]; - double lnp_los = logP_los_synth(x, length, params, lnp_star); - std::cerr << "# ln p(x_0) = " << lnp_los << std::endl; - - double *x_tmp = new double[length]; - double Theta_tmp[4]; - double sigma_Theta[4] = {0.1, 0.1, 0.1, 0.1}; - double sigma_RV = 0.05; - double sigma_lnEBV = 0.1; - double lnp_tmp; - double *lnp_star_tmp = new double[params.N_stars]; - double p; - - unsigned int N_steps = 1000000; - - TChain chain(length, N_steps); - TStats EBV_stats(N_DM); - - // In each step - unsigned int N_star = 0; - unsigned int N_accept_star = 0; - unsigned int N_los = 0; - unsigned int N_accept_los = 0; - bool accept; - bool burn_in = true; - for(unsigned int i=0; i lnp_star[n]) { - accept = true; - } else { - p = gsl_rng_uniform(r); - if((p > 0.) && (log(p) < lnp_tmp - lnp_star[n])) { - accept = true; - } - } - - if(accept) { - if(!burn_in) { N_accept_star++; } - for(size_t k=0; k<4; k++) { x[1+N_DM+4*n+k] = Theta_tmp[k]; } - lnp_los += lnp_tmp - lnp_star[n]; - lnp_star[n] = lnp_tmp; - } - } - - // Step reddening profile - if(!burn_in) { N_los++; } - for(size_t k=0; k lnp_los) { - accept = true; - } else if(log(gsl_rng_uniform(r)) < lnp_tmp - lnp_los) { - accept = true; - } - - if(accept) { - if(!burn_in) { N_accept_los++; } - for(size_t k=0; k<1+N_DM; k++) { x[k] = x_tmp[k]; } - for(size_t k=0; kEBV / (double)N_DM * gsl_ran_chisq(r, 1.); } // Delta_EBV + + // Random starting point for each star + TSED sed_tmp(true); + for(size_t i = 1 + params.N_DM; i < 1 + params.N_DM + 4*params.N_stars; i += 4) { + x[i] = 5. + 13.*gsl_rng_uniform(r); + double logMass, logtau, FeH, tau; + bool in_lib = false; + while(!in_lib) { + logMass = gsl_ran_gaussian_ziggurat(r, 0.5); + tau = -1.; + while(tau <= 0.) { + tau = 1.e9 * (5. + gsl_ran_gaussian_ziggurat(r, 2.)); + } + logtau = log10(tau); + FeH = -1.0 + gsl_ran_gaussian_ziggurat(r, 1.); + + in_lib = stellar_model.get_sed(logMass, logtau, FeH, sed_tmp); + } + x[i+1] = logMass; + x[i+2] = logtau; + x[i+3] = FeH; + } + + params.update_EBV_interp(x); + double *lnp_star = new double[params.N_stars]; + double lnp_los = logP_los_synth(x, length, params, lnp_star); + std::cerr << "# ln p(x_0) = " << lnp_los << std::endl; + + double *x_tmp = new double[length]; + double Theta_tmp[4]; + double sigma_Theta[4] = {0.1, 0.1, 0.1, 0.1}; + double sigma_RV = 0.05; + double sigma_lnEBV = 0.1; + double lnp_tmp; + double *lnp_star_tmp = new double[params.N_stars]; + double p; + + unsigned int N_steps = 1000000; + + TChain chain(length, N_steps); + TStats EBV_stats(N_DM); + + // In each step + unsigned int N_star = 0; + unsigned int N_accept_star = 0; + unsigned int N_los = 0; + unsigned int N_accept_los = 0; + bool accept; + bool burn_in = true; + for(unsigned int i=0; i lnp_star[n]) { + accept = true; + } else { + p = gsl_rng_uniform(r); + if((p > 0.) && (log(p) < lnp_tmp - lnp_star[n])) { + accept = true; + } + } + + if(accept) { + if(!burn_in) { N_accept_star++; } + for(size_t k=0; k<4; k++) { x[1+N_DM+4*n+k] = Theta_tmp[k]; } + lnp_los += lnp_tmp - lnp_star[n]; + lnp_star[n] = lnp_tmp; + } + } + + // Step reddening profile + if(!burn_in) { N_los++; } + for(size_t k=0; k lnp_los) { + accept = true; + } else if(log(gsl_rng_uniform(r)) < lnp_tmp - lnp_los) { + accept = true; + } + + if(accept) { + if(!burn_in) { N_accept_los++; } + for(size_t k=0; k<1+N_DM; k++) { x[k] = x_tmp[k]; } + for(size_t k=0; kEBV / (double)params.N_DM * gsl_ran_chisq(r, 1.); } - - // Stars - TSED sed_tmp(true); - for(size_t i = 1 + params.N_DM; i < 1 + params.N_DM + 4*params.N_stars; i += 4) { - // DM - x[i] = 5. + 13. * gsl_rng_uniform(r); - - // Stellar type - double logMass, logtau, FeH, tau; - bool in_lib = false; - while(!in_lib) { - logMass = gsl_ran_gaussian_ziggurat(r, 0.5); - tau = -1.; - while(tau <= 0.) { - tau = 1.e9 * (5. + gsl_ran_gaussian_ziggurat(r, 2.)); - } - logtau = log10(tau); - FeH = -1.0 + gsl_ran_gaussian_ziggurat(r, 1.); - - in_lib = params.synth_stellar_model->get_sed(logMass, logtau, FeH, sed_tmp); - } - x[i+1] = logMass; - x[i+2] = logtau; - x[i+3] = FeH; - } + assert(N == 1 + params.N_DM + 4*params.N_stars); + + // R_V + x[0] = 3.1 + gsl_ran_gaussian_ziggurat(r, 0.2); + + // Delta_EBV + for(size_t i=0; iEBV / (double)params.N_DM * gsl_ran_chisq(r, 1.); } + + // Stars + TSED sed_tmp(true); + for(size_t i = 1 + params.N_DM; i < 1 + params.N_DM + 4*params.N_stars; i += 4) { + // DM + x[i] = 5. + 13. * gsl_rng_uniform(r); + + // Stellar type + double logMass, logtau, FeH, tau; + bool in_lib = false; + while(!in_lib) { + logMass = gsl_ran_gaussian_ziggurat(r, 0.5); + tau = -1.; + while(tau <= 0.) { + tau = 1.e9 * (5. + gsl_ran_gaussian_ziggurat(r, 2.)); + } + logtau = log10(tau); + FeH = -1.0 + gsl_ran_gaussian_ziggurat(r, 1.); + + in_lib = params.synth_stellar_model->get_sed(logMass, logtau, FeH, sed_tmp); + } + x[i+1] = logMass; + x[i+2] = logtau; + x[i+3] = FeH; + } } double logP_los_simple_synth(const double *x, unsigned int N, TMCMCParams ¶ms) { - params.update_EBV_interp(x); - return logP_los_synth(x, N, params, NULL); + params.update_EBV_interp(x); + return logP_los_synth(x, N, params, NULL); } void sample_model_affine_synth(TGalacticLOSModel &galactic_model, TSyntheticStellarModel &stellar_model, TExtinctionModel &extinction_model, TStellarData &stellar_data) { - unsigned int N_DM = 20; - double DM_min = 4.; - double DM_max = 19.; - TMCMCParams params(&galactic_model, &stellar_model, NULL, &extinction_model, &stellar_data, N_DM, DM_min, DM_max); - TStats EBV_stats(N_DM); - - unsigned int N_steps = 100; - unsigned int N_samplers = 4; - - TAffineSampler::pdf_t f_pdf = &logP_los_simple_synth; - TAffineSampler::rand_state_t f_rand_state = &gen_rand_state_synth; - - std::cerr << "# Setting up sampler" << std::endl; - unsigned int ndim = 1 + params.N_DM + 4*params.N_stars; - TParallelAffineSampler sampler(f_pdf, f_rand_state, ndim, 10*ndim, params, EBV_stats, N_samplers); - - std::cerr << "# Burn-in" << std::endl; - sampler.set_scale(1.1); - sampler.set_replacement_bandwidth(0.5); - sampler.step(N_steps, false, 0, 0.01); - sampler.clear(); - std::cerr << "# Main run" << std::endl; - sampler.step(N_steps, true, 0, 0.01); - - std::cout << "Sampler stats:" << std::endl; - sampler.print_stats(); - std::cout << std::endl; - - std::cout << "E(B-V) statistics:" << std::endl; - EBV_stats.print(); - std::cout << std::endl; - - /* - std::cerr << "# ln p(x) = " << lnp_los << std::endl; - std::cout.precision(4); - std::cerr << std::endl; - std::cerr << "# % acceptance: " << 100. * (double)N_accept_star / (double)N_star << " (stars)" << std::endl; - std::cerr << " " << 100. * (double)N_accept_los / (double)N_los << " (extinction)" << std::endl; - std::cerr << "# R_V = " << x[0] << std::endl << std::endl; - std::cerr << "# DM E(B-V)" << std::endl; - std::cerr << "# =============" << std::endl; - for(double DM=5.; DM<20.; DM+=1.) { - std::cerr << "# " << DM << " " << params.get_EBV(DM) << std::endl; - } - std::cerr << std::endl; - EBV_stats.print(); - std::cerr << std::endl; - */ + unsigned int N_DM = 20; + double DM_min = 4.; + double DM_max = 19.; + TMCMCParams params(&galactic_model, &stellar_model, NULL, &extinction_model, &stellar_data, N_DM, DM_min, DM_max); + TStats EBV_stats(N_DM); + + unsigned int N_steps = 100; + unsigned int N_samplers = 4; + + TAffineSampler::pdf_t f_pdf = &logP_los_simple_synth; + TAffineSampler::rand_state_t f_rand_state = &gen_rand_state_synth; + + std::cerr << "# Setting up sampler" << std::endl; + unsigned int ndim = 1 + params.N_DM + 4*params.N_stars; + TParallelAffineSampler sampler(f_pdf, f_rand_state, ndim, 10*ndim, params, EBV_stats, N_samplers); + + std::cerr << "# Burn-in" << std::endl; + sampler.set_scale(1.1); + sampler.set_replacement_bandwidth(0.5); + sampler.step(N_steps, false, 0, 0.01); + sampler.clear(); + std::cerr << "# Main run" << std::endl; + sampler.step(N_steps, true, 0, 0.01); + + std::cout << "Sampler stats:" << std::endl; + sampler.print_stats(); + std::cout << std::endl; + + std::cout << "E(B-V) statistics:" << std::endl; + EBV_stats.print(); + std::cout << std::endl; + + /* + std::cerr << "# ln p(x) = " << lnp_los << std::endl; + std::cout.precision(4); + std::cerr << std::endl; + std::cerr << "# % acceptance: " << 100. * (double)N_accept_star / (double)N_star << " (stars)" << std::endl; + std::cerr << " " << 100. * (double)N_accept_los / (double)N_los << " (extinction)" << std::endl; + std::cerr << "# R_V = " << x[0] << std::endl << std::endl; + std::cerr << "# DM E(B-V)" << std::endl; + std::cerr << "# =============" << std::endl; + for(double DM=5.; DM<20.; DM+=1.) { + std::cerr << "# " << DM << " " << params.get_EBV(DM) << std::endl; + } + std::cerr << std::endl; + EBV_stats.print(); + std::cerr << std::endl; + */ } void gen_rand_state_indiv_synth(double *const x, unsigned int N, gsl_rng *r, TMCMCParams ¶ms) { - assert(N == 5); - - // Stars - TSED sed_tmp(true); - - // E(B-V) - x[0] = params.EBV_floor + (1.5 * params.data->EBV - params.EBV_floor) * (0.05 + 0.9 * gsl_rng_uniform(r)); - - // DM - x[1] = params.DM_min + (params.DM_max - params.DM_min) * (0.05 + 0.9 * gsl_rng_uniform(r)); - - // Stellar type - double logMass, logtau, FeH, tau; - bool in_lib = false; - while(!in_lib) { - logMass = gsl_ran_gaussian_ziggurat(r, 0.5); - //tau = -1.; - //while(tau <= 0.) { - // tau = 1.e9 * (5. + gsl_ran_gaussian_ziggurat(r, 2.)); - //} - //logtau = log10(tau); - logtau = 8. + gsl_ran_gaussian_ziggurat(r, 1.); - FeH = -1.0 + gsl_ran_gaussian_ziggurat(r, 1.); - - in_lib = params.synth_stellar_model->get_sed(logMass, logtau, FeH, sed_tmp); - } - x[2] = logMass; - x[3] = logtau; - x[4] = FeH; - - if(params.vary_RV) { - double RV = -1.; - while((RV <= 2.1) || (RV >= 5.)) { - RV = params.RV_mean + gsl_ran_gaussian_ziggurat(r, 1.5*params.RV_variance*params.RV_variance); - } - x[5] = RV; - } + assert(N == 5); + + // Stars + TSED sed_tmp(true); + + // E(B-V) + x[0] = params.EBV_floor + (1.5 * params.data->EBV - params.EBV_floor) * (0.05 + 0.9 * gsl_rng_uniform(r)); + + // DM + x[1] = params.DM_min + (params.DM_max - params.DM_min) * (0.05 + 0.9 * gsl_rng_uniform(r)); + + // Stellar type + double logMass, logtau, FeH, tau; + bool in_lib = false; + while(!in_lib) { + logMass = gsl_ran_gaussian_ziggurat(r, 0.5); + //tau = -1.; + //while(tau <= 0.) { + // tau = 1.e9 * (5. + gsl_ran_gaussian_ziggurat(r, 2.)); + //} + //logtau = log10(tau); + logtau = 8. + gsl_ran_gaussian_ziggurat(r, 1.); + FeH = -1.0 + gsl_ran_gaussian_ziggurat(r, 1.); + + in_lib = params.synth_stellar_model->get_sed(logMass, logtau, FeH, sed_tmp); + } + x[2] = logMass; + x[3] = logtau; + x[4] = FeH; + + if(params.vary_RV) { + double RV = -1.; + while((RV <= 2.1) || (RV >= 5.)) { + RV = params.RV_mean + gsl_ran_gaussian_ziggurat(r, 1.5*params.RV_variance*params.RV_variance); + } + x[5] = RV; + } } void gen_rand_state_indiv_emp(double *const x, unsigned int N, gsl_rng *r, TMCMCParams ¶ms) { - if(params.vary_RV) { assert(N == 5); } else { assert(N == 4); } - - // Stars - TSED sed_tmp(true); - - // Stellar type - double Mr, FeH; - Mr = -0.5 + 15.5 * gsl_rng_uniform(r); - FeH = -2.45 + 2.4 * gsl_rng_uniform(r); - - x[2] = Mr; - x[3] = FeH; - - double RV = params.RV_mean;; - if(params.vary_RV) { - RV = -1.; - while((RV <= 2.1) || (RV >= 5.)) { - RV = params.RV_mean + gsl_ran_gaussian_ziggurat(r, 1.5*params.RV_variance*params.RV_variance); - } - x[4] = RV; - } - - // Guess E(B-V) on the basis of other parameters - - // Choose first two bands that have been observed - /*int b1, b2; - for(b1=0; b1star[params.idx_star].err[b1] < 1.e9) { - break; - } - } - for(b2=b1+1; b2star[params.idx_star].err[b2] < 1.e9) { - break; - } - } - - // Color excess - TSED * tmp_sed = new TSED(true); - params.emp_stellar_model->get_sed(Mr, FeH, *tmp_sed); - - double mod_color = tmp_sed->absmag[b2] - tmp_sed->absmag[b1]; - double obs_color = params.data->star[params.idx_star].m[b2] - params.data->star[params.idx_star].m[b1]; - - // Reddening vector - double R_XY = params.ext_model->get_A(RV, b2) - params.ext_model->get_A(RV, b1); - - // E(B-V) - for(int i=0; i<5; i++) { - x[0] = (obs_color - mod_color) / R_XY + gsl_ran_gaussian_ziggurat(r, 0.1); - if((x[0] > params.EBV_floor) && (x[0] < 8.)) { // Accept first guess above E(B-V) floor - break; - } else if(i == 4) { // Revert to dumb, uniform guess - //#pragma omp critical - //{ - //std::cout << " = " << x[0] << " >~ " << 8. << std::endl; - //} - x[0] = fabs(gsl_ran_gaussian_ziggurat(r, 0.1)); - //x[0] = params.EBV_floor + (1.5 * params.data->EBV - params.EBV_floor) * (0.05 + 0.9 * gsl_rng_uniform(r)); - } - }*/ - - TSED * tmp_sed = new TSED(true); - params.emp_stellar_model->get_sed(Mr, FeH, *tmp_sed); - - double mod_color, obs_color, R_XY; - - double inv_sigma2_sum = 0.; - double weighted_sum = 0.; - double sigma1, sigma2; - - for(int b1=0; b1absmag[b2] - tmp_sed->absmag[b1]; - obs_color = params.data->star[params.idx_star].m[b2] - params.data->star[params.idx_star].m[b1]; - R_XY = params.ext_model->get_A(RV, b2) - params.ext_model->get_A(RV, b1); - - sigma1 = params.data->star[params.idx_star].err[b1]; - sigma2 = params.data->star[params.idx_star].err[b2]; - - weighted_sum += (obs_color - mod_color) / R_XY / (sigma1*sigma1 + sigma2*sigma2); - inv_sigma2_sum += 1. / (sigma1*sigma1 + sigma2*sigma2); - } - } - - double EBV_est = weighted_sum / inv_sigma2_sum; - - for(int i=0; i<5; i++) { - x[0] = EBV_est + gsl_ran_gaussian_ziggurat(r, 0.1); - if((x[0] > params.EBV_floor) && (x[0] < 8.)) { // Accept first guess above E(B-V) floor - break; - } else if(i == 4) { // Revert to dumber guess - //#pragma omp critical - //{ - //std::cout << " = " << x[0] << " >~ " << 8. << std::endl; - //} - if(EBV_est > 8.) { - x[0] = 8. - fabs(gsl_ran_gaussian_ziggurat(r, 0.1)); - } else { - x[0] = fabs(gsl_ran_gaussian_ziggurat(r, 0.1)); - } - //x[0] = params.EBV_floor + (1.5 * params.data->EBV - params.EBV_floor) * (0.05 + 0.9 * gsl_rng_uniform(r)); - } - } - - // Guess distance on the basis of model magnitudes vs. observed apparent magnitudes - inv_sigma2_sum = 0.; - weighted_sum = 0.; - - double sigma; - double reddened_mag, obs_mag, maglim; - double max_DM = inf_replacement; - - for(int i=0; istar[params.idx_star].err[i]; - reddened_mag = tmp_sed->absmag[i] + x[0] * params.ext_model->get_A(RV, i); - obs_mag = params.data->star[params.idx_star].m[i]; - maglim = params.data->star[params.idx_star].maglimit[i]; - if(obs_mag > maglim) { - obs_mag = maglim; - } - weighted_sum += (obs_mag - reddened_mag) / (sigma * sigma); - inv_sigma2_sum += 1. / (sigma * sigma); - - // Update maximum allowable distance modulus - if(maglim - reddened_mag < max_DM) { - max_DM = maglim - reddened_mag; - } - } - - double DM_est = weighted_sum / inv_sigma2_sum; - - x[1] = DM_est + gsl_ran_gaussian_ziggurat(r, 0.1); - - // Adjust distance to ensure that star is observable - if(x[1] > max_DM + 0.25) { - //#pragma omp critical (cout) - //{ - //std::cerr << "DM: " << x[1] << " --> "; - x[1] = max_DM + gsl_ran_gaussian_ziggurat(r, 0.1); - //std::cerr << x[1] << std::endl; - //} - } - - /*#pragma omp critical (cout) - { - //std::cerr << " " << x[0] << " " << max_DM; - for(int i=0; iabsmag[i] + x[0] * params.ext_model->get_A(RV, i) + x[1]; - } - std::cerr << std::endl; - }*/ - - // Don't allow the distance guess to be crazy - /*if((x[1] < params.DM_min - 2.) || (x[1] > params.DM_max)) { - #pragma omp critical - { - std::cerr << "!!! DM = " << x[1]; - x[1] = params.DM_min + (params.DM_max - params.DM_min) * (0.05 + 0.9 * gsl_rng_uniform(r)); - std::cerr << " --> " << x[1] << " !!!" << std::endl; - } - }*/ - - //#pragma omp critical (cout) - //{ - //std::cout << "E(B-V) guess: " << x[0] << " = " << "E(" << b2 << " - " << b1 << ") / (R_" << b2 << " - R_" << b1 << ")" << std::endl; - //std::cout << "DM guess: " << x[1] << std::endl; - //} - - /*#pragma omp critical (cout) - { - std::cerr << "Guess: " << x[0] << " " << x[1] << " " << x[2] << " " << x[3] << std::endl; - }*/ - - delete tmp_sed; + if(params.vary_RV) { assert(N == 5); } else { assert(N == 4); } + + // Stars + TSED sed_tmp(true); + + // Stellar type + double Mr, FeH; + Mr = -0.5 + 15.5 * gsl_rng_uniform(r); + FeH = -2.45 + 2.4 * gsl_rng_uniform(r); + + x[2] = Mr; + x[3] = FeH; + + double RV = params.RV_mean;; + if(params.vary_RV) { + RV = -1.; + while((RV <= 2.1) || (RV >= 5.)) { + RV = params.RV_mean + gsl_ran_gaussian_ziggurat(r, 1.5*params.RV_variance*params.RV_variance); + } + x[4] = RV; + } + + // Guess E(B-V) on the basis of other parameters + + // Choose first two bands that have been observed + /*int b1, b2; + for(b1=0; b1star[params.idx_star].err[b1] < 1.e9) { + break; + } + } + for(b2=b1+1; b2star[params.idx_star].err[b2] < 1.e9) { + break; + } + } + + // Color excess + TSED * tmp_sed = new TSED(true); + params.emp_stellar_model->get_sed(Mr, FeH, *tmp_sed); + + double mod_color = tmp_sed->absmag[b2] - tmp_sed->absmag[b1]; + double obs_color = params.data->star[params.idx_star].m[b2] - params.data->star[params.idx_star].m[b1]; + + // Reddening vector + double R_XY = params.ext_model->get_A(RV, b2) - params.ext_model->get_A(RV, b1); + + // E(B-V) + for(int i=0; i<5; i++) { + x[0] = (obs_color - mod_color) / R_XY + gsl_ran_gaussian_ziggurat(r, 0.1); + if((x[0] > params.EBV_floor) && (x[0] < 8.)) { // Accept first guess above E(B-V) floor + break; + } else if(i == 4) { // Revert to dumb, uniform guess + //#pragma omp critical + //{ + //std::cout << " = " << x[0] << " >~ " << 8. << std::endl; + //} + x[0] = fabs(gsl_ran_gaussian_ziggurat(r, 0.1)); + //x[0] = params.EBV_floor + (1.5 * params.data->EBV - params.EBV_floor) * (0.05 + 0.9 * gsl_rng_uniform(r)); + } + }*/ + + TSED * tmp_sed = new TSED(true); + params.emp_stellar_model->get_sed(Mr, FeH, *tmp_sed); + + double mod_color, obs_color, R_XY; + + double inv_sigma2_sum = 0.; + double weighted_sum = 0.; + double sigma1, sigma2; + + for(int b1=0; b1absmag[b2] - tmp_sed->absmag[b1]; + obs_color = params.data->star[params.idx_star].m[b2] - params.data->star[params.idx_star].m[b1]; + R_XY = params.ext_model->get_A(RV, b2) - params.ext_model->get_A(RV, b1); + + sigma1 = params.data->star[params.idx_star].err[b1]; + sigma2 = params.data->star[params.idx_star].err[b2]; + + weighted_sum += (obs_color - mod_color) / R_XY / (sigma1*sigma1 + sigma2*sigma2); + inv_sigma2_sum += 1. / (sigma1*sigma1 + sigma2*sigma2); + } + } + + double EBV_est = weighted_sum / inv_sigma2_sum; + + for(int i=0; i<5; i++) { + x[0] = EBV_est + gsl_ran_gaussian_ziggurat(r, 0.1); + if((x[0] > params.EBV_floor) && (x[0] < 8.)) { // Accept first guess above E(B-V) floor + break; + } else if(i == 4) { // Revert to dumber guess + //#pragma omp critical + //{ + //std::cout << " = " << x[0] << " >~ " << 8. << std::endl; + //} + if(EBV_est > 8.) { + x[0] = 8. - fabs(gsl_ran_gaussian_ziggurat(r, 0.1)); + } else { + x[0] = fabs(gsl_ran_gaussian_ziggurat(r, 0.1)); + } + //x[0] = params.EBV_floor + (1.5 * params.data->EBV - params.EBV_floor) * (0.05 + 0.9 * gsl_rng_uniform(r)); + } + } + + // Guess distance on the basis of model magnitudes vs. observed apparent magnitudes + inv_sigma2_sum = 0.; + weighted_sum = 0.; + + double sigma; + double reddened_mag, obs_mag, maglim; + double max_DM = inf_replacement; + + for(int i=0; istar[params.idx_star].err[i]; + reddened_mag = tmp_sed->absmag[i] + x[0] * params.ext_model->get_A(RV, i); + obs_mag = params.data->star[params.idx_star].m[i]; + maglim = params.data->star[params.idx_star].maglimit[i]; + if(obs_mag > maglim) { + obs_mag = maglim; + } + weighted_sum += (obs_mag - reddened_mag) / (sigma * sigma); + inv_sigma2_sum += 1. / (sigma * sigma); + + // Update maximum allowable distance modulus + if(maglim - reddened_mag < max_DM) { + max_DM = maglim - reddened_mag; + } + } + + double DM_est = weighted_sum / inv_sigma2_sum; + + x[1] = DM_est + gsl_ran_gaussian_ziggurat(r, 0.1); + + // Adjust distance to ensure that star is observable + if(x[1] > max_DM + 0.25) { + //#pragma omp critical (cout) + //{ + //std::cerr << "DM: " << x[1] << " --> "; + x[1] = max_DM + gsl_ran_gaussian_ziggurat(r, 0.1); + //std::cerr << x[1] << std::endl; + //} + } + + /*#pragma omp critical (cout) + { + //std::cerr << " " << x[0] << " " << max_DM; + for(int i=0; iabsmag[i] + x[0] * params.ext_model->get_A(RV, i) + x[1]; + } + std::cerr << std::endl; + }*/ + + // Don't allow the distance guess to be crazy + /*if((x[1] < params.DM_min - 2.) || (x[1] > params.DM_max)) { + #pragma omp critical + { + std::cerr << "!!! DM = " << x[1]; + x[1] = params.DM_min + (params.DM_max - params.DM_min) * (0.05 + 0.9 * gsl_rng_uniform(r)); + std::cerr << " --> " << x[1] << " !!!" << std::endl; + } + }*/ + + //#pragma omp critical (cout) + //{ + //std::cout << "E(B-V) guess: " << x[0] << " = " << "E(" << b2 << " - " << b1 << ") / (R_" << b2 << " - R_" << b1 << ")" << std::endl; + //std::cout << "DM guess: " << x[1] << std::endl; + //} + + /*#pragma omp critical (cout) + { + std::cerr << "Guess: " << x[0] << " " << x[1] << " " << x[2] << " " << x[3] << std::endl; + }*/ + + delete tmp_sed; } double logP_indiv_simple_synth(const double *x, unsigned int N, TMCMCParams ¶ms) { - if(x[0] < params.EBV_floor) { return neg_inf_replacement; } - double RV; - double logp = 0; - if(params.vary_RV) { - RV = x[5]; - if((RV <= 2.1) || (RV >= 5.)) { - return neg_inf_replacement; - } - logp = -0.5*(RV-params.RV_mean)*(RV-params.RV_mean)/params.RV_variance; - } else { - RV = params.RV_mean; - } - logp += logP_single_star_synth(x+1, x[0], RV, *params.gal_model, *params.synth_stellar_model, *params.ext_model, params.data->star[params.idx_star], NULL); - return logp; + if(x[0] < params.EBV_floor) { return neg_inf_replacement; } + double RV; + double logp = 0; + if(params.vary_RV) { + RV = x[5]; + if((RV <= 2.1) || (RV >= 5.)) { + return neg_inf_replacement; + } + logp = -0.5*(RV-params.RV_mean)*(RV-params.RV_mean)/params.RV_variance; + } else { + RV = params.RV_mean; + } + logp += logP_single_star_synth(x+1, x[0], RV, *params.gal_model, *params.synth_stellar_model, *params.ext_model, params.data->star[params.idx_star], NULL); + return logp; } double logP_indiv_simple_emp(const double *x, unsigned int N, TMCMCParams ¶ms) { - if(x[0] < params.EBV_floor) { return neg_inf_replacement; } - double RV; - double logp = 0; - if(params.vary_RV) { - RV = x[4]; - if((RV <= 2.1) || (RV >= 5.)) { - return neg_inf_replacement; - } - logp = -0.5*(RV-params.RV_mean)*(RV-params.RV_mean)/params.RV_variance; - } else { - RV = params.RV_mean; - } - if(params.use_priors) { - logp += logP_single_star_emp(x+1, x[0], RV, *params.gal_model, *params.emp_stellar_model, *params.ext_model, params.data->star[params.idx_star], NULL); - } else { - logp += logP_single_star_emp_noprior(x+1, x[0], RV, *params.gal_model, *params.emp_stellar_model, *params.ext_model, params.data->star[params.idx_star], NULL); - } - return logp; + if(x[0] < params.EBV_floor) { return neg_inf_replacement; } + double RV; + double logp = 0; + if(params.vary_RV) { + RV = x[4]; + if((RV <= 2.1) || (RV >= 5.)) { + return neg_inf_replacement; + } + logp = -0.5*(RV-params.RV_mean)*(RV-params.RV_mean)/params.RV_variance; + } else { + RV = params.RV_mean; + } + if(params.use_priors) { + logp += logP_single_star_emp(x+1, x[0], RV, *params.gal_model, *params.emp_stellar_model, *params.ext_model, params.data->star[params.idx_star], NULL); + } else { + logp += logP_single_star_emp_noprior(x+1, x[0], RV, *params.gal_model, *params.emp_stellar_model, *params.ext_model, params.data->star[params.idx_star], NULL); + } + return logp; } void sample_indiv_synth(std::string &out_fname, TMCMCOptions &options, TGalacticLOSModel& galactic_model, TSyntheticStellarModel& stellar_model, TExtinctionModel& extinction_model, TStellarData& stellar_data, TImgStack& img_stack, std::vector &conv, std::vector &lnZ, double RV_sigma, double minEBV, const bool saveSurfs, const bool gatherSurfs, int verbosity) { - // Parameters must be consistent - cannot save surfaces without gathering them - assert(!(saveSurfs & (!gatherSurfs))); - - unsigned int N_DM = 20; - double DM_min = 4.; - double DM_max = 19.; - TMCMCParams params(&galactic_model, &stellar_model, NULL, &extinction_model, &stellar_data, N_DM, DM_min, DM_max); - params.EBV_floor = minEBV; - - if(RV_sigma > 0.) { - params.vary_RV = true; - params.RV_variance = RV_sigma*RV_sigma; - } - - double min[2] = {0., DM_min}; - double max[2] = {5., DM_max}; - unsigned int N_bins[2] = {500, 120}; - TRect rect(min, max, N_bins); - - if(gatherSurfs) { - img_stack.resize(params.N_stars); - img_stack.set_rect(rect); - } - - TImgWriteBuffer *imgBuffer = NULL; - if(saveSurfs) { imgBuffer = new TImgWriteBuffer(rect, params.N_stars); } - - TNullLogger logger; - - unsigned int max_attempts = 3; - unsigned int N_steps = options.steps; - unsigned int N_samplers = options.samplers; - unsigned int N_runs = options.N_runs; - unsigned int ndim; - - if(params.vary_RV) { ndim = 6; } else { ndim = 5; } - - double *GR = new double[ndim]; - double GR_threshold = 1.1; - - TAffineSampler::pdf_t f_pdf = &logP_indiv_simple_synth; - TAffineSampler::rand_state_t f_rand_state = &gen_rand_state_indiv_synth; - - if(verbosity >= 1) { - std::cout << std::endl; - } - - unsigned int N_nonconv = 0; - - TChainWriteBuffer chainBuffer(ndim, 100, params.N_stars); - std::stringstream group_name; - group_name << "/" << stellar_data.pix_name; - - timespec t_start, t_write, t_end; - - for(size_t n=0; n= 2) { - std::cout << "Star #" << n+1 << " of " << params.N_stars << std::endl; - std::cout << "====================================" << std::endl; - } - - //std::cerr << "# Setting up sampler" << std::endl; - TParallelAffineSampler sampler(f_pdf, f_rand_state, ndim, N_samplers*ndim, params, logger, N_runs); - sampler.set_scale(1.2); - sampler.set_replacement_bandwidth(0.2); - sampler.set_sigma_min(0.02); - - //std::cerr << "# Burn-in" << std::endl; - sampler.step(N_steps, false, 0., 0.2); - sampler.clear(); - - //std::cerr << "# Main run" << std::endl; - bool converged = false; - size_t attempt; - for(attempt = 0; (attempt < max_attempts) && (!converged); attempt++) { - sampler.step((1< GR_threshold) { - converged = false; - if(attempt != max_attempts-1) { - sampler.clear(); - //logger.clear(); - } - break; - } - } - } - - clock_gettime(CLOCK_MONOTONIC, &t_write); - - // Compute evidence - TChain chain = sampler.get_chain(); - double lnZ_tmp = chain.get_ln_Z_harmonic(true, 10., 0.25, 0.05); - //if(isinf(lnZ_tmp)) { lnZ_tmp = neg_inf_replacement; } - - // Save thinned chain - chainBuffer.add(chain, converged, lnZ_tmp, GR); - - // Save binned p(DM, EBV) surface - if(gatherSurfs) { - chain.get_image(*(img_stack.img[n]), rect, 0, 1, true, 0.02, 0.1, 30.); - } - if(saveSurfs) { imgBuffer->add(*(img_stack.img[n])); } - - lnZ.push_back(lnZ_tmp); - conv.push_back(converged); - - clock_gettime(CLOCK_MONOTONIC, &t_end); - - //std::cout << "Sampler stats:" << std::endl; - if(verbosity >= 2) { - sampler.print_stats(); - std::cout << std::endl; - } - - if(!converged) { - N_nonconv++; - if(verbosity >= 2) { - std::cout << "# Failed to converge." << std::endl; - } - } - - if(verbosity >= 2) { - std::cout << "# Number of steps: " << (1<<(attempt-1))*N_steps << std::endl; - std::cout << "# Time elapsed: " << std::setprecision(2) << (t_end.tv_sec - t_start.tv_sec) + 1.e-9*(t_end.tv_nsec - t_start.tv_nsec) << " s" << std::endl; - std::cout << "# Sample time: " << std::setprecision(2) << (t_write.tv_sec - t_start.tv_sec) + 1.e-9*(t_write.tv_nsec - t_start.tv_nsec) << " s" << std::endl; - std::cout << "# Write time: " << std::setprecision(2) << (t_end.tv_sec - t_write.tv_sec) + 1.e-9*(t_end.tv_nsec - t_write.tv_nsec) << " s" << std::endl << std::endl; - } - } - - chainBuffer.write(out_fname, group_name.str(), "stellar chains"); - if(saveSurfs) { imgBuffer->write(out_fname, group_name.str(), "stellar pdfs"); } - - if(verbosity >= 1) { - std::cout << "====================================" << std::endl; - std::cout << std::endl; - std::cout << "# Failed to converge " << N_nonconv << " of " << params.N_stars << " times (" << std::setprecision(2) << 100.*(double)N_nonconv/(double)(params.N_stars) << " %)." << std::endl; - std::cout << std::endl; - std::cout << "====================================" << std::endl; - } - - if(imgBuffer != NULL) { delete imgBuffer; } - delete[] GR; + // Parameters must be consistent - cannot save surfaces without gathering them + assert(!(saveSurfs & (!gatherSurfs))); + + unsigned int N_DM = 20; + double DM_min = 4.; + double DM_max = 19.; + TMCMCParams params(&galactic_model, &stellar_model, NULL, &extinction_model, &stellar_data, N_DM, DM_min, DM_max); + params.EBV_floor = minEBV; + + if(RV_sigma > 0.) { + params.vary_RV = true; + params.RV_variance = RV_sigma*RV_sigma; + } + + double min[2] = {0., DM_min}; + double max[2] = {7., DM_max}; + unsigned int N_bins[2] = {700, 120}; + TRect rect(min, max, N_bins); + + if(gatherSurfs) { + img_stack.resize(params.N_stars); + img_stack.set_rect(rect); + } + + TImgWriteBuffer *imgBuffer = NULL; + if(saveSurfs) { imgBuffer = new TImgWriteBuffer(rect, params.N_stars); } + + TNullLogger logger; + + unsigned int max_attempts = 3; + unsigned int N_steps = options.steps; + unsigned int N_samplers = options.samplers; + unsigned int N_runs = options.N_runs; + unsigned int ndim; + + if(params.vary_RV) { ndim = 6; } else { ndim = 5; } + + double *GR = new double[ndim]; + double GR_threshold = 1.1; + + TAffineSampler::pdf_t f_pdf = &logP_indiv_simple_synth; + TAffineSampler::rand_state_t f_rand_state = &gen_rand_state_indiv_synth; + + if(verbosity >= 1) { + std::cout << std::endl; + } + + unsigned int N_nonconv = 0; + + TChainWriteBuffer chainBuffer(ndim, 100, params.N_stars); + std::stringstream group_name; + group_name << "/" << stellar_data.pix_name; + + timespec t_start, t_write, t_end; + + for(size_t n=0; n= 2) { + std::cout << "Star #" << n+1 << " of " << params.N_stars << std::endl; + std::cout << "====================================" << std::endl; + } + + //std::cerr << "# Setting up sampler" << std::endl; + TParallelAffineSampler sampler(f_pdf, f_rand_state, ndim, N_samplers*ndim, params, logger, N_runs); + sampler.set_scale(1.2); + sampler.set_replacement_bandwidth(0.2); + sampler.set_sigma_min(0.02); + + //std::cerr << "# Burn-in" << std::endl; + sampler.step(N_steps, false, 0., 0.2); + sampler.clear(); + + //std::cerr << "# Main run" << std::endl; + bool converged = false; + size_t attempt; + for(attempt = 0; (attempt < max_attempts) && (!converged); attempt++) { + sampler.step((1< GR_threshold) { + converged = false; + if(attempt != max_attempts-1) { + sampler.clear(); + //logger.clear(); + } + break; + } + } + } + + clock_gettime(CLOCK_MONOTONIC, &t_write); + + // Compute evidence + TChain chain = sampler.get_chain(); + double lnZ_tmp = chain.get_ln_Z_harmonic(true, 10., 0.25, 0.05); + //if(isinf(lnZ_tmp)) { lnZ_tmp = neg_inf_replacement; } + + // Save thinned chain + chainBuffer.add(chain, converged, lnZ_tmp, GR); + + // Save binned p(DM, EBV) surface + if(gatherSurfs) { + chain.get_image(*(img_stack.img[n]), rect, 0, 1, true, 1.0, 1.0, 30., true); + } + if(saveSurfs) { imgBuffer->add(*(img_stack.img[n])); } + + lnZ.push_back(lnZ_tmp); + conv.push_back(converged); + + clock_gettime(CLOCK_MONOTONIC, &t_end); + + //std::cout << "Sampler stats:" << std::endl; + if(verbosity >= 2) { + sampler.print_stats(); + std::cout << std::endl; + } + + if(!converged) { + N_nonconv++; + if(verbosity >= 2) { + std::cout << "# Failed to converge." << std::endl; + } + } + + if(verbosity >= 2) { + std::cout << "# Number of steps: " << (1<<(attempt-1))*N_steps << std::endl; + std::cout << "# Time elapsed: " << std::setprecision(2) << (t_end.tv_sec - t_start.tv_sec) + 1.e-9*(t_end.tv_nsec - t_start.tv_nsec) << " s" << std::endl; + std::cout << "# Sample time: " << std::setprecision(2) << (t_write.tv_sec - t_start.tv_sec) + 1.e-9*(t_write.tv_nsec - t_start.tv_nsec) << " s" << std::endl; + std::cout << "# Write time: " << std::setprecision(2) << (t_end.tv_sec - t_write.tv_sec) + 1.e-9*(t_end.tv_nsec - t_write.tv_nsec) << " s" << std::endl << std::endl; + } + } + + chainBuffer.write(out_fname, group_name.str(), "stellar chains"); + if(saveSurfs) { imgBuffer->write(out_fname, group_name.str(), "stellar pdfs"); } + + if(verbosity >= 1) { + std::cout << "====================================" << std::endl; + std::cout << std::endl; + std::cout << "# Failed to converge " << N_nonconv << " of " << params.N_stars << " times (" << std::setprecision(2) << 100.*(double)N_nonconv/(double)(params.N_stars) << " %)." << std::endl; + std::cout << std::endl; + std::cout << "====================================" << std::endl; + } + + if(imgBuffer != NULL) { delete imgBuffer; } + delete[] GR; } void sample_indiv_emp(std::string &out_fname, TMCMCOptions &options, TGalacticLOSModel& galactic_model, - TStellarModel& stellar_model, TExtinctionModel& extinction_model, TStellarData& stellar_data, - TImgStack& img_stack, std::vector &conv, std::vector &lnZ, - double RV_mean, double RV_sigma, double minEBV, - const bool saveSurfs, const bool gatherSurfs, const bool use_priors, int verbosity) { - // Parameters must be consistent - cannot save surfaces without gathering them - assert(!(saveSurfs & (!gatherSurfs))); - - unsigned int N_DM = 20; - double DM_min = 4.; - double DM_max = 19.; - TMCMCParams params(&galactic_model, NULL, &stellar_model, &extinction_model, &stellar_data, N_DM, DM_min, DM_max); - params.EBV_floor = minEBV; - params.use_priors = use_priors; - - params.RV_mean = RV_mean; - if(RV_sigma > 0.) { - params.vary_RV = true; - params.RV_variance = RV_sigma*RV_sigma; - } - - //std::string dim_name[5] = {"E(B-V)", "DM", "Mr", "FeH", "R_V"}; - - double min[2] = {minEBV, DM_min}; - double max[2] = {5., DM_max}; - unsigned int N_bins[2] = {500, 120}; - TRect rect(min, max, N_bins); - - if(gatherSurfs) { - img_stack.resize(params.N_stars); - img_stack.set_rect(rect); - } - TImgWriteBuffer *imgBuffer = NULL; - if(saveSurfs) { imgBuffer = new TImgWriteBuffer(rect, params.N_stars); } - - unsigned int max_attempts = 3; - unsigned int N_steps = options.steps; - unsigned int N_samplers = options.samplers; - unsigned int N_runs = options.N_runs; - unsigned int ndim; - - if(params.vary_RV) { ndim = 5; } else { ndim = 4; } - - double *GR = new double[ndim]; - double GR_threshold = 1.1; - - TNullLogger logger; - TAffineSampler::pdf_t f_pdf = &logP_indiv_simple_emp; - TAffineSampler::rand_state_t f_rand_state = &gen_rand_state_indiv_emp; - - timespec t_start, t_write, t_end; - - if(verbosity >= 1) { - std::cout << std::endl; - } - - unsigned int N_nonconv = 0; - - TChainWriteBuffer chainBuffer(ndim, 100, params.N_stars); - std::stringstream group_name; - group_name << "/" << stellar_data.pix_name; - - for(size_t n=0; n= 2) { - std::cout << "Star #" << n+1 << " of " << params.N_stars << std::endl; - std::cout << "====================================" << std::endl; - - std::cout << "mags = "; - for(unsigned int i=0; istar[n].m[i] << " "; - } - std::cout << std::endl; - std::cout << "errs = "; - for(unsigned int i=0; istar[n].err[i] << " "; - } - std::cout << std::endl; - std::cout << "maglimit = "; - for(unsigned int i=0; istar[n].maglimit[i] << " "; - } - std::cout << std::endl << std::endl; - } - - //std::cerr << "# Setting up sampler" << std::endl; - TParallelAffineSampler sampler(f_pdf, f_rand_state, ndim, N_samplers*ndim, params, logger, N_runs); - sampler.set_scale(1.5); - sampler.set_replacement_bandwidth(0.30); - sampler.set_replacement_accept_bias(1.e-5); - sampler.set_sigma_min(0.02); - - //std::cerr << "# Burn-in" << std::endl; - - // Burn-in - - // Round 1 (3/6) - sampler.step_MH(N_steps*(1./6.), false); - sampler.step(N_steps*(2./6.), false, 0., options.p_replacement); - - if(verbosity >= 2) { - std::cout << std::endl; - std::cout << "scale: ("; - std::cout << std::setprecision(2); - for(int k=0; kget_scale() << ((k == sampler.get_N_samplers() - 1) ? "" : ", "); - } - } - - // Remove spurious modes - sampler.set_replacement_accept_bias(1.e-2); - int N_steps_biased = N_steps*(1./6.); - if(N_steps_biased > 20) { N_steps_biased = 20; } - sampler.step(N_steps_biased, false, 0., 1.); - - sampler.tune_stretch(6, 0.30); - sampler.tune_MH(6, 0.30); - - if(verbosity >= 2) { - std::cout << ") -> ("; - for(int k=0; kget_scale() << ((k == sampler.get_N_samplers() - 1) ? "" : ", "); - } - std::cout << ")" << std::endl; - } - - // Round 2 (3/6) - sampler.set_replacement_accept_bias(0.); - sampler.step_MH(N_steps*(1./6.), false); - sampler.step(N_steps*(2./6.), false, 0., options.p_replacement); - - if(verbosity >= 2) { - std::cout << "scale: ("; - std::cout << std::setprecision(2); - for(int k=0; kget_scale() << ((k == sampler.get_N_samplers() - 1) ? "" : ", "); - } - } - - sampler.tune_stretch(6, 0.30); - sampler.tune_MH(6, 0.30); - - if(verbosity >= 2) { - std::cout << ") -> ("; - for(int k=0; kget_scale() << ((k == sampler.get_N_samplers() - 1) ? "" : ", "); - } - std::cout << ")" << std::endl; - std::cout << std::endl; - } - - sampler.clear(); - - //std::cerr << "# Main run" << std::endl; - - // Main run - bool converged = false; - size_t attempt; - for(attempt = 0; (attempt < max_attempts) && (!converged); attempt++) { - sampler.step((1< GR_threshold) { - converged = false; - if(attempt != max_attempts-1) { - sampler.clear(); - //logger.clear(); - } - break; - } - } - } - - clock_gettime(CLOCK_MONOTONIC, &t_write); - - // Compute evidence - TChain chain = sampler.get_chain(); - double lnZ_tmp = chain.get_ln_Z_harmonic(true, 10., 0.25, 0.05); - //if(isinf(lnZ_tmp)) { lnZ_tmp = neg_inf_replacement; } - - // Save thinned chain - chainBuffer.add(chain, converged, lnZ_tmp, GR); - - // Save binned p(DM, EBV) surface - if(gatherSurfs) { - chain.get_image(*(img_stack.img[n]), rect, 0, 1, true, 0.0125, 0.1, 30.); - } - if(saveSurfs) { imgBuffer->add(*(img_stack.img[n])); } - - lnZ.push_back(lnZ_tmp); - conv.push_back(converged); - - clock_gettime(CLOCK_MONOTONIC, &t_end); - - if(verbosity >= 2) { - sampler.print_stats(); - std::cout << std::endl; - } - - if(!converged) { - N_nonconv++; - if(verbosity >= 2) { - std::cout << "# Failed to converge." << std::endl; - } - } - - if(verbosity >= 2) { - std::cout << "# Number of steps: " << (1<<(attempt-1))*N_steps << std::endl; - std::cout << "# ln Z: " << lnZ.back() << std::endl; - std::cout << "# Time elapsed: " << std::setprecision(2) << (t_end.tv_sec - t_start.tv_sec) + 1.e-9*(t_end.tv_nsec - t_start.tv_nsec) << " s" << std::endl; - std::cout << "# Sample time: " << std::setprecision(2) << (t_write.tv_sec - t_start.tv_sec) + 1.e-9*(t_write.tv_nsec - t_start.tv_nsec) << " s" << std::endl; - std::cout << "# Write time: " << std::setprecision(2) << (t_end.tv_sec - t_write.tv_sec) + 1.e-9*(t_end.tv_nsec - t_write.tv_nsec) << " s" << std::endl << std::endl; - } - } - - chainBuffer.write(out_fname, group_name.str(), "stellar chains"); - if(saveSurfs) { imgBuffer->write(out_fname, group_name.str(), "stellar pdfs"); } - - if(verbosity >= 1) { - if(verbosity >= 2) { - std::cout << "====================================" << std::endl; - std::cout << std::endl; - } - std::cout << "# Failed to converge " << N_nonconv << " of " << params.N_stars << " times (" << std::setprecision(2) << 100.*(double)N_nonconv/(double)(params.N_stars) << " %)." << std::endl; - if(verbosity >= 2) { - std::cout << std::endl; - std::cout << "====================================" << std::endl << std::endl; - } - } - - if(imgBuffer != NULL) { delete imgBuffer; } - delete[] GR; + TStellarModel& stellar_model, TExtinctionModel& extinction_model, TEBVSmoothing& EBV_smoothing, + TStellarData& stellar_data, TImgStack& img_stack, std::vector &conv, std::vector &lnZ, + double RV_mean, double RV_sigma, double minEBV, const bool saveSurfs, const bool gatherSurfs, const bool use_priors, + int verbosity) { + // Parameters must be consistent - cannot save surfaces without gathering them + assert(!(saveSurfs & (!gatherSurfs))); + + unsigned int N_DM = 20; + double DM_min = 4.; + double DM_max = 19.; + TMCMCParams params(&galactic_model, NULL, &stellar_model, &extinction_model, &stellar_data, N_DM, DM_min, DM_max); + params.EBV_floor = minEBV; + params.use_priors = use_priors; + + params.RV_mean = RV_mean; + if(RV_sigma > 0.) { + params.vary_RV = true; + params.RV_variance = RV_sigma*RV_sigma; + } + + //std::string dim_name[5] = {"E(B-V)", "DM", "Mr", "FeH", "R_V"}; + + double min[2] = {minEBV, DM_min}; + double max[2] = {7., DM_max}; + unsigned int N_bins[2] = {700, 120}; + TRect rect(min, max, N_bins); + + if(gatherSurfs) { + img_stack.resize(params.N_stars); + img_stack.set_rect(rect); + } + TImgWriteBuffer *imgBuffer = NULL; + if(saveSurfs) { imgBuffer = new TImgWriteBuffer(rect, params.N_stars); } + + unsigned int max_attempts = 3; + unsigned int N_steps = options.steps; + unsigned int N_samplers = options.samplers; + unsigned int N_runs = options.N_runs; + unsigned int ndim; + + if(params.vary_RV) { ndim = 5; } else { ndim = 4; } + + double *GR = new double[ndim]; + double GR_threshold = 1.1; + + TNullLogger logger; + TAffineSampler::pdf_t f_pdf = &logP_indiv_simple_emp; + TAffineSampler::rand_state_t f_rand_state = &gen_rand_state_indiv_emp; + + timespec t_start, t_write, t_end; + + if(verbosity >= 1) { + std::cout << std::endl; + } + + unsigned int N_nonconv = 0; + + TChainWriteBuffer chainBuffer(ndim, 100, params.N_stars); + std::stringstream group_name; + group_name << "/" << stellar_data.pix_name; + + for(size_t n=0; n= 2) { + std::cout << "Star #" << n+1 << " of " << params.N_stars << std::endl; + std::cout << "====================================" << std::endl; + + std::cout << "mags = "; + for(unsigned int i=0; istar[n].m[i] << " "; + } + std::cout << std::endl; + std::cout << "errs = "; + for(unsigned int i=0; istar[n].err[i] << " "; + } + std::cout << std::endl; + std::cout << "maglimit = "; + for(unsigned int i=0; istar[n].maglimit[i] << " "; + } + std::cout << std::endl << std::endl; + } + + //std::cerr << "# Setting up sampler" << std::endl; + TParallelAffineSampler sampler(f_pdf, f_rand_state, ndim, N_samplers*ndim, params, logger, N_runs); + sampler.set_scale(1.5); + sampler.set_replacement_bandwidth(0.30); + sampler.set_replacement_accept_bias(1.e-5); + sampler.set_sigma_min(0.02); + + //std::cerr << "# Burn-in" << std::endl; + + // Burn-in + + // Round 1 (3/6) + sampler.step_MH(N_steps*(1./6.), false); + sampler.step(N_steps*(2./6.), false, 0., options.p_replacement); + + if(verbosity >= 2) { + std::cout << std::endl; + std::cout << "scale: ("; + std::cout << std::setprecision(2); + for(int k=0; kget_scale() << ((k == sampler.get_N_samplers() - 1) ? "" : ", "); + } + } + + // Remove spurious modes + sampler.set_replacement_accept_bias(1.e-2); + int N_steps_biased = N_steps*(1./6.); + if(N_steps_biased > 20) { N_steps_biased = 20; } + sampler.step(N_steps_biased, false, 0., 1.); + + sampler.tune_stretch(6, 0.30); + sampler.tune_MH(6, 0.30); + + if(verbosity >= 2) { + std::cout << ") -> ("; + for(int k=0; kget_scale() << ((k == sampler.get_N_samplers() - 1) ? "" : ", "); + } + std::cout << ")" << std::endl; + } + + // Round 2 (3/6) + sampler.set_replacement_accept_bias(0.); + sampler.step_MH(N_steps*(1./6.), false); + sampler.step(N_steps*(2./6.), false, 0., options.p_replacement); + + if(verbosity >= 2) { + std::cout << "scale: ("; + std::cout << std::setprecision(2); + for(int k=0; kget_scale() << ((k == sampler.get_N_samplers() - 1) ? "" : ", "); + } + } + + sampler.tune_stretch(6, 0.30); + sampler.tune_MH(6, 0.30); + + if(verbosity >= 2) { + std::cout << ") -> ("; + for(int k=0; kget_scale() << ((k == sampler.get_N_samplers() - 1) ? "" : ", "); + } + std::cout << ")" << std::endl; + std::cout << std::endl; + } + + sampler.clear(); + + //std::cerr << "# Main run" << std::endl; + + // Main run + bool converged = false; + size_t attempt; + for(attempt = 0; (attempt < max_attempts) && (!converged); attempt++) { + sampler.step((1< GR_threshold) { + converged = false; + if(attempt != max_attempts-1) { + sampler.clear(); + //logger.clear(); + } + break; + } + } + } + + clock_gettime(CLOCK_MONOTONIC, &t_write); + + // Compute evidence + TChain chain = sampler.get_chain(); + double lnZ_tmp = chain.get_ln_Z_harmonic(true, 10., 0.25, 0.05); + //if(isinf(lnZ_tmp)) { lnZ_tmp = neg_inf_replacement; } + + // Save thinned chain + chainBuffer.add(chain, converged, lnZ_tmp, GR); + + // Save binned p(DM, EBV) surface + if(gatherSurfs) { + chain.get_image(*(img_stack.img[n]), rect, 0, 1, true, 1.0, 1.0, 30., true); + } + + lnZ.push_back(lnZ_tmp); + conv.push_back(converged); + + clock_gettime(CLOCK_MONOTONIC, &t_end); + + if(verbosity >= 2) { + sampler.print_stats(); + std::cout << std::endl; + } + + if(!converged) { + N_nonconv++; + if(verbosity >= 2) { + std::cout << "# Failed to converge." << std::endl; + } + } + + if(verbosity >= 2) { + std::cout << "# Number of steps: " << (1<<(attempt-1))*N_steps << std::endl; + std::cout << "# ln Z: " << lnZ.back() << std::endl; + std::cout << "# Time elapsed: " << std::setprecision(2) << (t_end.tv_sec - t_start.tv_sec) + 1.e-9*(t_end.tv_nsec - t_start.tv_nsec) << " s" << std::endl; + std::cout << "# Sample time: " << std::setprecision(2) << (t_write.tv_sec - t_start.tv_sec) + 1.e-9*(t_write.tv_nsec - t_start.tv_nsec) << " s" << std::endl; + std::cout << "# Write time: " << std::setprecision(2) << (t_end.tv_sec - t_write.tv_sec) + 1.e-9*(t_end.tv_nsec - t_write.tv_nsec) << " s" << std::endl << std::endl; + } + } + + // Smooth the individual stellar surfaces along E(B-V) axis, with + // kernel that varies with E(B-V). + if(EBV_smoothing.get_pct_smoothing_max() > 0.) { + std::vector sigma_pix; + EBV_smoothing.calc_pct_smoothing(stellar_data.nside, min[0], max[0], N_bins[0], sigma_pix); + for(int i=0; iadd(*(img_stack.img[n])); + } + } + + chainBuffer.write(out_fname, group_name.str(), "stellar chains"); + if(saveSurfs) { imgBuffer->write(out_fname, group_name.str(), "stellar pdfs"); } + + if(verbosity >= 1) { + if(verbosity >= 2) { + std::cout << "====================================" << std::endl; + std::cout << std::endl; + } + std::cout << "# Failed to converge " << N_nonconv << " of " << params.N_stars << " times (" << std::setprecision(2) << 100.*(double)N_nonconv/(double)(params.N_stars) << " %)." << std::endl; + if(verbosity >= 2) { + std::cout << std::endl; + std::cout << "====================================" << std::endl << std::endl; + } + } + + if(imgBuffer != NULL) { delete imgBuffer; } + delete[] GR; +} + + +#ifdef _USE_PARALLEL_TEMPERING__ +// Sample individual star using parallel tempering +void sample_indiv_emp_pt( + std::string &out_fname, + TMCMCOptions &options, + TGalacticLOSModel& galactic_model, + TStellarModel& stellar_model, + TExtinctionModel& extinction_model, + TEBVSmoothing& EBV_smoothing, + TStellarData& stellar_data, + TImgStack& img_stack, + std::vector &conv, + std::vector &lnZ, + double RV_mean, double RV_sigma, double minEBV, + const bool saveSurfs, const bool gatherSurfs, + const bool use_priors, int verbosity) +{ + // Parameters must be consistent - cannot save surfaces without gathering them + assert(!(saveSurfs & (!gatherSurfs))); + + unsigned int N_DM = 20; + double DM_min = 4.; + double DM_max = 19.; + TMCMCParams params(&galactic_model, NULL, &stellar_model, &extinction_model, &stellar_data, N_DM, DM_min, DM_max); + params.EBV_floor = minEBV; + params.use_priors = use_priors; + + params.RV_mean = RV_mean; + if(RV_sigma > 0.) { + params.vary_RV = true; + params.RV_variance = RV_sigma*RV_sigma; + } + + //std::string dim_name[5] = {"E(B-V)", "DM", "Mr", "FeH", "R_V"}; + + double min[2] = {minEBV, DM_min}; + double max[2] = {7., DM_max}; + unsigned int N_bins[2] = {700, 120}; + TRect rect(min, max, N_bins); + + if(gatherSurfs) { + img_stack.resize(params.N_stars); + img_stack.set_rect(rect); + } + TImgWriteBuffer *imgBuffer = NULL; + if(saveSurfs) { + imgBuffer = new TImgWriteBuffer(rect, params.N_stars); + } + + unsigned int max_attempts = 3; + unsigned int N_steps = options.steps; + unsigned int N_samplers = options.samplers; + unsigned int N_runs = options.N_runs; + unsigned int ndim; + + if(params.vary_RV) { ndim = 5; } else { ndim = 4; } + + double *GR = new double[ndim]; + double GR_threshold = 1.1; + + // Parallel tempering parameters + cppsampler::pdensity ln_prior = [](double* x) { return 0.; }; + cppsampler::pdensity lnL = [¶ms, ndim](double* x) { + double res = logP_indiv_simple_emp(x, ndim, params); + // std::cerr << "ln p( "; + // for(int k=0; k= 2) { + std::cout << "Star #" << n+1 << " of " << params.N_stars << std::endl; + std::cout << "====================================" << std::endl; + + std::cout << "mags = "; + for(unsigned int i=0; istar[n].m[i] << " "; + } + std::cout << std::endl; + std::cout << "errs = "; + for(unsigned int i=0; istar[n].err[i] << " "; + } + std::cout << std::endl; + std::cout << "maglimit = "; + for(unsigned int i=0; istar[n].maglimit[i] << " "; + } + std::cout << std::endl << std::endl; + } + + // Set up the parallel tempering sampler + cppsampler::PTSampler pt_sampler(lnL, ln_prior, ndim, + n_temperatures, temperature_spacing); + + // Seed the sampler + gsl_rng *r; + seed_gsl_rng(&r); + + cppsampler::vector_generator rand_state = [ndim, ¶ms, &r]() { + cppsampler::shared_vector x0 = std::make_shared >(ndim, 0.); + gen_rand_state_indiv_emp(x0->data(), ndim, r, params); + return x0; + }; + + pt_sampler.set_state(rand_state); + + gsl_rng_free(r); + + // Burn-in + cppsampler::PTTuningParameters tune_params; + tune_params.n_rounds = 10; + tune_params.n_swaps_per_round = 20; + tune_params.n_steps_per_swap = 20; + tune_params.step_accept = 0.25; + + pt_sampler.tune_all(tune_params); + + int n_steps_per_swap = 2; + int n_swaps = N_steps / n_steps_per_swap; + + pt_sampler.step_multiple(n_swaps/4, n_steps_per_swap); + + tune_params.n_rounds = 20; + tune_params.n_swaps_per_round = 20; + tune_params.n_steps_per_swap = 20; + + pt_sampler.tune_all(tune_params); + + pt_sampler.step_multiple(n_swaps/4, n_steps_per_swap); + + std::cerr << std::endl + << "MH acceptance: " + << 100. * pt_sampler.get_sampler(0)->accept_frac() + << "%" + << std::endl << std::endl; + + std::cerr << std::endl + << "swap acceptance: " + << 100. * pt_sampler.swap_accept_frac() + << "%" + << std::endl << std::endl; + + std::cerr << "beta = "; + for(auto beta : *pt_sampler.get_beta()) { + std::cerr << beta << " "; + } + std::cerr << std::endl; + + pt_sampler.clear_chain(); + + // Main sampling phase + pt_sampler.step_multiple(n_swaps, n_steps_per_swap); + + std::cerr << std::endl + << "MH acceptance: " + << 100. * pt_sampler.get_sampler(0)->accept_frac() + << "%" + << std::endl << std::endl; + + std::cerr << std::endl + << "swap acceptance: " + << 100. * pt_sampler.swap_accept_frac() + << "%" + << std::endl << std::endl; + + clock_gettime(CLOCK_MONOTONIC, &t_write); + + std::cerr << "done sampling." << std::endl; + + // Copy over chain + std::shared_ptr pt_chain = pt_sampler.get_chain(0); + TChain chain(ndim, pt_chain->get_length()+1); + cppsampler::shared_const_vector chain_el = pt_chain->get_elements(); + cppsampler::shared_const_vector chain_w = pt_chain->get_weights(); + cppsampler::shared_const_vector chain_lnp = pt_chain->get_lnL(); + for(int k=0; ksize(); k++) { + chain.add_point( + chain_el->data()+ndim*k, + chain_lnp->at(k), + chain_w->at(k) + ); + } + + std::cerr << "done copying chain." << std::endl; + + // Compute evidence + // cppsampler::BasicRandGenerator rand_gen; + // double lnZ_tmp = rand_gen.uniform(); + double lnZ_tmp = chain.get_ln_Z_harmonic(true, 10., 0.25, 0.05); + + std::cerr << "calculated lnZ" << std::endl; + + // Save thinned chain + bool converged = true; // TODO: calculate convergence and GR diagnostic. + chainBuffer.add(chain, converged, lnZ_tmp, GR); + + std::cerr << "added to chain buffer." << std::endl; + + // Save binned p(DM, EBV) surface + if(gatherSurfs) { + chain.get_image(*(img_stack.img[n]), rect, 0, 1, true, 1.0, 1.0, 30., true); + } + + std::cerr << "calculated image." << std::endl; + + // Save convergence/goodness-of-fit statistics + lnZ.push_back(lnZ_tmp); + conv.push_back(converged); + + clock_gettime(CLOCK_MONOTONIC, &t_end); + + // Report timing + if(verbosity >= 2) { + std::cout << "# Number of steps: " << N_steps << std::endl; + std::cout << "# ln Z: " << lnZ.back() << std::endl; + std::cout << "# Time elapsed: " << std::setprecision(2) << (t_end.tv_sec - t_start.tv_sec) + 1.e-9*(t_end.tv_nsec - t_start.tv_nsec) << " s" << std::endl; + std::cout << "# Sample time: " << std::setprecision(2) << (t_write.tv_sec - t_start.tv_sec) + 1.e-9*(t_write.tv_nsec - t_start.tv_nsec) << " s" << std::endl; + std::cout << "# Write time: " << std::setprecision(2) << (t_end.tv_sec - t_write.tv_sec) + 1.e-9*(t_end.tv_nsec - t_write.tv_nsec) << " s" << std::endl << std::endl; + } + } + + // Smooth the individual stellar surfaces along E(B-V) axis, with + // kernel that varies with E(B-V). + if(EBV_smoothing.get_pct_smoothing_max() > 0.) { + std::cerr << "Smoothing images along reddening axis." << std::endl; + std::vector sigma_pix; + EBV_smoothing.calc_pct_smoothing(stellar_data.nside, min[0], max[0], N_bins[0], sigma_pix); + for(int i=0; iadd(*(img_stack.img[n])); + } + } + + chainBuffer.write(out_fname, group_name.str(), "stellar chains"); + if(saveSurfs) { imgBuffer->write(out_fname, group_name.str(), "stellar pdfs"); } + + std::cerr << "cleaning up." << std::endl; + + if(imgBuffer != NULL) { delete imgBuffer; } + delete[] GR; } +#endif // _USE_PARALLEL_TERMPERING /************************************************************************* - * + * * Auxiliary Functions - * + * *************************************************************************/ #ifndef __SEED_GSL_RNG_ #define __SEED_GSL_RNG_ // Seed a gsl_rng with the Unix time in nanoseconds inline void seed_gsl_rng(gsl_rng **r) { - timespec t_seed; - clock_gettime(CLOCK_REALTIME, &t_seed); - long unsigned int seed = 1e9*(long unsigned int)t_seed.tv_sec; - seed += t_seed.tv_nsec; - *r = gsl_rng_alloc(gsl_rng_taus); - gsl_rng_set(*r, seed); + timespec t_seed; + clock_gettime(CLOCK_REALTIME, &t_seed); + long unsigned int seed = 1e9*(long unsigned int)t_seed.tv_sec; + seed += t_seed.tv_nsec; + seed ^= (long unsigned int)getpid(); + *r = gsl_rng_alloc(gsl_rng_taus); + gsl_rng_set(*r, seed); } #endif void rand_vector(double*const x, double* min, double* max, size_t N, gsl_rng* r) { - for(size_t i=0; i +#include + #include #include #include #include +#ifdef _USE_PARALLEL_TERMPERING +#include +#endif // _USE_PARALLEL_TERMPERING + #include "h5utils.h" #include "model.h" @@ -61,10 +67,14 @@ // Wrapper for parameters needed by the sampler struct TMCMCParams { - TMCMCParams(TGalacticLOSModel* _gal_model, TSyntheticStellarModel* _synth_stellar_model, TStellarModel* _emp_stellar_model, TExtinctionModel* _ext_model, - TStellarData* _data, unsigned int _N_DM, double _DM_min, double _DM_max); + TMCMCParams(TGalacticLOSModel* _gal_model, + TSyntheticStellarModel* _synth_stellar_model, + TStellarModel* _emp_stellar_model, + TExtinctionModel* _ext_model, + TStellarData* _data, + unsigned int _N_DM, double _DM_min, double _DM_max); ~TMCMCParams(); - + // Model TSyntheticStellarModel *synth_stellar_model; TStellarModel *emp_stellar_model; @@ -73,25 +83,25 @@ struct TMCMCParams { double EBV_SFD, EBV_floor; double DM_min, DM_max; unsigned int N_DM, N_stars; - + // Data TStellarData *data; - + // Single-star probability density floor double lnp0; - + // Auxiliary info for E(B-V) curve TLinearInterp *EBV_interp; double EBV_min, EBV_max; void update_EBV_interp(const double* x); double get_EBV(double DM); - + // Index of star to fit, when sampling from individual stellar posteriors unsigned int idx_star; - + bool vary_RV; double RV_mean, RV_variance; - + bool use_priors; }; @@ -121,10 +131,29 @@ void sample_indiv_synth(std::string &out_fname, TMCMCOptions &options, TGalactic int verbosity=1); void sample_indiv_emp(std::string &out_fname, TMCMCOptions &options, TGalacticLOSModel& galactic_model, - TStellarModel& stellar_model, TExtinctionModel& extinction_model, TStellarData& stellar_data, - TImgStack& img_stack, std::vector &conv, std::vector &lnZ, - double RV_mean=3.1, double RV_sigma=-1., double minEBV=0., const bool saveSurfs=false, const bool gatherSurfs=true, - const bool use_priors=true, int verbosity=1); + TStellarModel& stellar_model, TExtinctionModel& extinction_model, TEBVSmoothing& EBV_smoothing, + TStellarData& stellar_data, TImgStack& img_stack, std::vector &conv, std::vector &lnZ, + double RV_mean=3.1, double RV_sigma=-1., double minEBV=0., const bool saveSurfs=false, + const bool gatherSurfs=true, const bool use_priors=true, int verbosity=1); + +#ifdef _USE_PARALLEL_TEMPERING__ +void sample_indiv_emp_pt( + std::string &out_fname, + TMCMCOptions &options, + TGalacticLOSModel& galactic_model, + TStellarModel& stellar_model, + TExtinctionModel& extinction_model, + TEBVSmoothing& EBV_smoothing, + TStellarData& stellar_data, + TImgStack& img_stack, + std::vector &conv, + std::vector &lnZ, + double RV_mean=3.1, double RV_sigma=-1., double minEBV=0., + const bool saveSurfs=false, const bool gatherSurfs=true, + const bool use_priors=true, int verbosity=1 +); +#endif // _USE_PARALLEL_TEMPERING__ + // Auxiliary functions void seed_gsl_rng(gsl_rng **r); diff --git a/src/star_exact.cpp b/src/star_exact.cpp new file mode 100644 index 0000000..ab17560 --- /dev/null +++ b/src/star_exact.cpp @@ -0,0 +1,931 @@ + +#include "star_exact.h" + + +/* + * Pretty-print various objects + */ + +void print_float(double x, std::ostream& o, + int width=10, int precision=5, + std::string pm="") { + std::stringstream s; + s << std::fixed << std::setw(width) << std::setprecision(precision) << x; + o << s.str(); +} + + +void print_matrix(cv::Mat& mat, std::ostream& s, + int width=10, int precision=5) { + for(int j=0; j(j,k), s, width, precision); + } + s << std::endl; + } +} + + +/* + * LinearFitParams + */ + +LinearFitParams::LinearFitParams(unsigned int n_dim) + : _n_dim(n_dim), mean(n_dim), inv_cov(n_dim, n_dim), + chi2(std::numeric_limits::infinity()) +{} + + +/* + * Grid evaluation of stellar parameters (E, \mu, M_r, [Fe/H]) + */ + +void star_covariance(TStellarData::TMagnitudes& mags_obs, + TExtinctionModel& ext_model, + double& inv_cov_00, double& inv_cov_01, double& inv_cov_11, + double RV) { + // Various useful terms + double inv_sigma2 = 0.; // 1 / sigma_i^2 + double A_over_sigma2 = 0.; // A_i / sigma_i^2 + double A2_over_sigma2 = 0.; // A_i^2 / sigma_i^2 + + for(int i=0; i extinction mapping. +double calc_star_chi2(TStellarData::TMagnitudes& mags_obs, + TExtinctionModel& ext_model, + TSED& mags_model, + double mu, double E, double RV) { + double chi2 = 0.; + + for(int i=0; i star_max_likelihood( + TSED& mags_model, + TStellarData::TMagnitudes& mags_obs, + TExtinctionModel& ext_model, + double RV) { + // Create empty return class + std::shared_ptr ret = std::make_shared(2); + + // Various useful terms + double inv_sigma2 = 0.; // 1 / sigma_i^2 + double A_over_sigma2 = 0.; // A_i / sigma_i^2 + double A2_over_sigma2 = 0.; // A_i^2 / sigma_i^2 + double dm_over_sigma2 = 0.; // (m_i - M_i) / sigma_i^2 + double dm_A_over_sigma2 = 0.; // (m_i - M_i) A_i / sigma_i^2 + + for(int i=0; imean(0) = mu; + ret->mean(1) = E; + + // Compute inverse covariance + ret->inv_cov(0,0) = inv_sigma2; + ret->inv_cov(0,1) = A_over_sigma2; + ret->inv_cov(1,0) = A_over_sigma2; + ret->inv_cov(1,1) = A2_over_sigma2; + + // Compute best chi^2 by plugging in ML (mu, E) + double chi2 = 0.; + + for(int i=0; ichi2 = chi2; + + return ret; +} + + +void gaussian_filter(std::shared_ptr p, + TRect& grid, cv::Mat& img, + double n_sigma, int min_width) { + // Determine sigma along each axis + double det = p->inv_cov(0,0) * p->inv_cov(1,1) - p->inv_cov(0,1) * p->inv_cov(1,0) + 1.e-5; + double sigma[2] = { + sqrt(p->inv_cov(1,1) / det), + sqrt(p->inv_cov(0,0) / det) + }; + + // Determine dimensions of filter + int width[2]; + + for(unsigned int i=0; i<2; i++) { + width[i] = std::max(min_width, (int)(ceil(sigma[i] / grid.dx[i]))); + } + + // std::cerr << "width = (" << width[0] << ", " << width[1] << ")" << std::endl; + + // std::cerr << "initializing img" << std::endl; + img = cv::Mat::zeros(2*width[0]+1, 2*width[1]+1, CV_FLOATING_TYPE); + + // Evaluate filter at each point + // std::cerr << "evaluating image" << std::endl; + double dx, dy; + double cxx, cxy, cyy; + for(int i=0; i<(int)(2*width[0]+1); i++) { + dx = (i - width[0]) * grid.dx[0]; + cxx = p->inv_cov(0,0) * dx*dx; + + for(int j=0; j<2*width[1]+1; j++) { + dy = (j - width[1]) * grid.dx[1]; + cxy = p->inv_cov(0,1) * dx*dy; + cyy = p->inv_cov(1,1) * dy*dy; + + // std::cerr << " (" << i << ", " << j << ")" << std::endl; + // std::cerr << " width = (" << 2*width[0]+1 << ", " << 2*width[1]+1 << ")" << std::endl; + + img.at(i, j) += exp(-0.5 * (cxx + 2*cxy + cyy)); + } + } + // std::cerr << "done creating filter" << std::endl; +} + + +void gaussian_filter(double inv_cov_00, double inv_cov_01, double inv_cov_11, + TRect& grid, cv::Mat& img, + double n_sigma, int min_width, + double add_diagonal=-1., + int subsample=5, int verbosity=0) { + // Add extra smoothing along each axis + if(add_diagonal > 0.) { + double diag[2] = { + add_diagonal*grid.dx[0], + add_diagonal*grid.dx[1] + }; + + // std::cerr << "diagonal = (" << diag[0] << ", " << diag[1] << ")" << std::endl; + + double det = inv_cov_00 * inv_cov_11 - inv_cov_01 * inv_cov_01; + double cov_00 = inv_cov_11 / det; + double cov_11 = inv_cov_00 / det; + double cov_01 = -inv_cov_01 / det; + + cov_00 += diag[0] * diag[0]; + cov_11 += diag[1] * diag[1]; + + det = cov_00 * cov_11 - cov_01 * cov_01; + + inv_cov_00 = cov_11 / det; + inv_cov_11 = cov_00 / det; + inv_cov_01 = -cov_01 / det; + } + + // Determine sigma along each axis + double det = inv_cov_00 * inv_cov_11 - inv_cov_01 * inv_cov_01 + 1.e-5; + double sigma[2] = { + sqrt(inv_cov_11 / det),// + diag[0]*diag[0]), + sqrt(inv_cov_00 / det) // + diag[1]*diag[1]) + }; + + + // Determine dimensions of filter + int width[2]; + + for(unsigned int i=0; i<2; i++) { + width[i] = std::max(min_width, (int)(ceil(n_sigma * sigma[i] / grid.dx[i]))); + } + + if(verbosity >= 2) { + std::cerr << "sigma -> (" << sigma[0] << ", " << sigma[1] << ")" << std::endl; + std::cerr << "width = (" << width[0] << ", " << width[1] << ")" << std::endl; + } + + // std::cerr << "initializing img" << std::endl; + int w = 2 * width[0] + 1; + int h = 2 * width[1] + 1; + + // Size of sub-sampled image + int w_sub = subsample * w; + int h_sub = subsample * h; + + // Center of sub-sampled image + double w0 = 0.5 * (double)(w_sub - 1); + double h0 = 0.5 * (double)(h_sub - 1); + + // Create zeroed sub-sampled image + cv::Mat img_sub = cv::Mat::zeros(w_sub, h_sub, CV_FLOATING_TYPE); + + // std::cerr << std::endl + // << "inv_cov_?? : " + // << inv_cov_00 << " " + // << inv_cov_01 << " " + // << inv_cov_11 << std::endl + // << std::endl; + + // Evaluate filter at each point + // std::cerr << "evaluating image" << std::endl; + // double sum = 0; + double dx, dy; + double cxx, cxy, cyy; + for(int i=0; i(i, j) += weight; + // sum += weight; + } + } + // std::cerr << "done creating filter" << std::endl; + + // img.resize(h, w) + cv::Mat img_down; + cv::resize(img_sub, img_down, cv::Size(h, w), 0, 0, cv::INTER_AREA); + + img = img_down; + img /= img.at(width[0], width[1]); + + // std::cerr << "size = " << img_sub.rows << ", " << img_sub.cols << std::endl; + // std::cerr << "size = " << img_down.rows << ", " << img_down.cols << std::endl; +} + + + + +double integrate_ML_solution( + TStellarModel& stellar_model, + TGalacticLOSModel& los_model, + TStellarData::TMagnitudes& mags_obs, + TExtinctionModel& ext_model, + TImgStack& img_stack, + unsigned int img_idx, + bool save_gaussians, + std::vector& fit_centers, + std::vector& fit_icov, + bool use_priors, + bool use_gaia, + double RV, int verbosity) +{ + // + TSED sed; + unsigned int N_Mr = stellar_model.get_N_Mr(); + unsigned int N_FeH = stellar_model.get_N_FeH(); + double Mr, FeH; + + // std::cerr << "N_Mr = " << N_Mr << std::endl; + // std::cerr << "N_FeH = " << N_FeH << std::endl; + + // Calculate covariance of ML solution for (mu, E) + double inv_cov_00, inv_cov_01, inv_cov_11; + + star_covariance(mags_obs, ext_model, + inv_cov_00, inv_cov_01, inv_cov_11, + RV); + + // Set image of p(mu, E) to zero + if (!img_stack.initialize_to_zero(img_idx)) { + std::cerr << "Failed to initialize image to zero!" << std::endl; + } + + // Calculate ML (E, mu), chi^2 and prior for each (Mr, [Fe/H]) pair + std::vector E_ML; + std::vector mu_ML; + std::vector chi2_ML; + std::vector prior_ML; + + unsigned int N_reserve = N_Mr*N_FeH + 1; + E_ML.reserve(N_reserve); + mu_ML.reserve(N_reserve); + chi2_ML.reserve(N_reserve); + prior_ML.reserve(N_reserve); + + for(int Mr_idx=0; Mr_idx::infinity(); + } + } + + if(std::isnan(chi2) || std::isinf(chi2)) { + chi2 = std::numeric_limits::infinity(); + } + + // std::cerr << "p(FeH = " << FeH << ") = " << prior << std::endl; + + E_ML.push_back(E); + mu_ML.push_back(mu); + chi2_ML.push_back(chi2); + prior_ML.push_back(prior); + } + } + + // Calculate best prior and likelihood (minimum chi^2) + double prior_max = 0.; + if(use_priors) { + prior_max = *std::max_element(prior_ML.begin(), prior_ML.end()); + } + + double chi2_min = *std::min_element(chi2_ML.begin(), chi2_ML.end()); + + if(verbosity >= 2) { + std::cerr << "prior_max = " << prior_max << std::endl; + std::cerr << "chi2_min = " << chi2_min << std::endl; + } + + assert( E_ML.size() == mu_ML.size() ); + assert( chi2_ML.size() == mu_ML.size() ); + assert( prior_ML.size() == mu_ML.size() ); + + //std::vector save_list; // List of Gaussians to save + //save_list.reserve(mu_ML.size()); + double delta_logp_threshold = -8.; + + // Interpolation information + unsigned int img_idx0, img_idx1; + double a0, a1; + + std::vector log_p_all; + log_p_all.reserve(mu_ML.size()); + + double chi2_min_filtered = std::numeric_limits::infinity(); + + for(int k=0; kget_interpolant( + E_ML.at(k), mu_ML.at(k), + img_idx0, img_idx1, + a0, a1 + ); + + // bool in_bounds = img_stack.rect->get_index(E_ML.at(k), mu_ML.at(k), img_idx0, img_idx1); + + if(in_bounds) { + double p = exp(log_p); + //if((a0 < 0.) || (a0 > 1.) || (a1 < 0.) || (a1 > 1.)) { + // std::cerr << "(a0, a1) = (" << a0 << ", " << a1 << ")" << std::endl; + //} + //if((p < 0.) || std::isnan(p)) { + // std::cerr << "p = " << p << std::endl; + //} + + // Interpolate between bins + img_stack.img[img_idx]->at(img_idx0, img_idx1) += (1-a0) * (1-a1) * p; + img_stack.img[img_idx]->at(img_idx0+1, img_idx1) += a0 * (1-a1) * p; + img_stack.img[img_idx]->at(img_idx0, img_idx1+1) += (1-a0) * a1 * p; + img_stack.img[img_idx]->at(img_idx0+1, img_idx1+1) += a0 * a1 * p; + + if(chi2_ML.at(k) < chi2_min_filtered) { + chi2_min_filtered = chi2_ML.at(k); + } + // Choose whether or not to save this point + //if(log_p > delta_logp_threshold) { + // save_list.push_back(k); + //} + } + } + + // Filtered version of chi^2, excluding out-of-bounds (mu,E) values + //std::vector chi2_filtered; + //chi2_filtered.reserve(save_list.size()); + //for(auto i : save_list) { + // chi2_filtered.push_back(chi2_ML.at(i)); + //} + //double chi2_min_filtered = 1.e9; + //if(save_list.size()) { + // chi2_min_filtered = *std::min_element(chi2_filtered.begin(), chi2_filtered.end()); + //} + + //for(int j=0; jN_bins[0]; j++) { + // for(int k=0; kN_bins[1]; k++) { + // double val_tmp = img_stack.img[img_idx]->at(j, k); + // if((val_tmp < 0.) || std::isnan(val_tmp)) { + // std::cerr << "img[" << j << ", " << k << "] = " << val_tmp << std::endl; + // } + // } + //} + + // Smooth PDF with covariance of the ML solution + cv::Mat cov_img; + gaussian_filter(inv_cov_11, inv_cov_01, inv_cov_00, + *(img_stack.rect), cov_img, 5, 2, 1.0, + 5, verbosity); + + //print_matrix(cov_img, std::cerr); + + cv::Mat filtered_img = cv::Mat::zeros( + img_stack.rect->N_bins[0], + img_stack.rect->N_bins[1], + CV_FLOATING_TYPE + ); + cv::filter2D(*img_stack.img[img_idx], filtered_img, CV_FLOATING_TYPE, cov_img); + *img_stack.img[img_idx] = cv::max(filtered_img, 0.); // Copy over matrix, setting negative values to zero + + //for(int j=0; jN_bins[0]; j++) { + // for(int k=0; kN_bins[1]; k++) { + // double val_tmp = img_stack.img[img_idx]->at(j, k); + // if(val_tmp < 0.) { + // std::cerr << "img'[" << j << ", " << k << "] = " << val_tmp << std::endl; + // } + // } + //} + + // Stores chosen Gaussians + if(save_gaussians) { + // Construct discrete distribution + std::vector p_all; + p_all.reserve(mu_ML.size()); + double lnp_max = *std::max_element( + log_p_all.begin(), + log_p_all.end() + ); + for(auto lnp : log_p_all) { + p_all.push_back(std::exp(lnp-lnp_max)); + //std::cout << lnp - lnp_max << std::endl; + } + std::discrete_distribution d( + p_all.begin(), + p_all.end() + ); + + // Create pseudorandom number generator + std::mt19937 r; + std::random_device rd; + r.seed(rd()); + + // Draw n samples + int n_samples = 250; + fit_centers.reserve(n_samples); + + for(int i=0; i 1.e9)) { + continue; + } + n_passbands++; + } + if(use_gaia) { + if(mags_obs.pi_err < mags_obs.pi) { + n_passbands++; + } + } + + if(verbosity >= 2) { + std::cerr << "# of passbands: " << n_passbands + << std::endl; + std::cerr << "chi^2 / passband: " + << chi2_min_filtered / n_passbands + << std::endl; + } + + return chi2_min_filtered / n_passbands; +} + +void grid_eval_stars(TGalacticLOSModel& los_model, + TExtinctionModel& ext_model, + TStellarModel& stellar_model, + TStellarData& stellar_data, + TEBVSmoothing& EBV_smoothing, + TImgStack& img_stack, + std::vector& chi2, + bool save_surfs, + bool save_gaussians, + std::string out_fname, + bool use_priors, + bool use_gaia, + double RV, int verbosity) { + // Timing + auto t_start = std::chrono::steady_clock::now(); + + // Set up image stack for stellar PDFs + double min[2] = {-0.2, 3.75}; // (E, DM) + double max[2] = { 7.2, 19.25}; // (E, DM) + unsigned int N_bins[2] = {740, 124}; + TRect rect(min, max, N_bins); + img_stack.set_rect(rect); + + // Loop over all stars and evaluate PDFs on grid in (mu, E) + int n_stars = stellar_data.star.size(); + chi2.clear(); + + // Name of group to save data to + std::stringstream group_name; + group_name << "/" << stellar_data.pix_name; + + // Create empty vector of stellar data to save + std::vector > fit_centers; + std::vector fit_icovs; + fit_centers.reserve(n_stars); + fit_icovs.reserve(n_stars); + + for(int i=0; i= 2) { + std::cerr << "Star " << i+1 << " of " << n_stars << std::endl; + } + + fit_centers.push_back( + std::vector() + ); + + double chi2_min = integrate_ML_solution( + stellar_model, los_model, + stellar_data[i], ext_model, + img_stack, i, + save_gaussians, + fit_centers.at(i), + fit_icovs, + use_priors, + use_gaia, + RV, + verbosity + ); + chi2.push_back(chi2_min); + } + + // Save individual Gaussians for each star + if(save_gaussians) { + save_gridstars( + out_fname, + group_name.str(), + "gridstars", + fit_centers, + fit_icovs + ); + } + + // Save chi^2/passband for each star + //std::cerr << "Saving chi^2/passband for stars ..." << std::endl; + std::unique_ptr file = H5Utils::openFile(out_fname); + if(file) { + std::unique_ptr chi2_dset = H5Utils::createDataSet( + *file, + group_name.str(), + "star_chi2", + chi2 + ); + //std::cerr << "chi^2 values written." << std::endl; + } else { + std::cerr << "! Failed to open " << out_fname << " !" << std::endl; + } + + // Crop to correct (E, DM) range + img_stack.crop(0., 7., 4., 19.); + + // Smooth the individual stellar surfaces along E(B-V) axis, with + // kernel that varies with E(B-V). + auto t_smooth = std::chrono::steady_clock::now(); + + if(EBV_smoothing.get_pct_smoothing_max() > 0.) { + std::cerr << "Smoothing images along reddening axis." << std::endl; + std::vector sigma_pix; + EBV_smoothing.calc_pct_smoothing( + stellar_data.nside, + img_stack.rect->min[0], + img_stack.rect->max[0], + img_stack.rect->N_bins[0], + sigma_pix + ); + for(int i=0; irows << ", " + // << img_stack.img[n]->cols << ")" << std::endl; + img_buffer.add(*(img_stack.img[n])); + } + + img_buffer.write(out_fname, group_name.str(), "stellar pdfs"); + } + + auto t_end = std::chrono::steady_clock::now(); + + std::chrono::duration dt_sample = t_smooth - t_start; + std::chrono::duration dt_smooth = t_write - t_smooth; + std::chrono::duration dt_write = t_end - t_write; + std::chrono::duration dt_total = t_end - t_start; + + if(verbosity >= 1) { + std::cerr << "Done with grid evaluation for all stars." + << std::endl << std::endl; + std::cerr << "Time elapsed / star:" << std::endl + << " * sample: " << dt_sample.count() / n_stars << " ms" + << std::endl + << " * smooth: " << dt_smooth.count() / n_stars << " ms" + << std::endl + << " * write: " << dt_write.count() / n_stars << " ms" + << std::endl + << " * total: " << dt_total.count() / n_stars << " ms" + << std::endl << std::endl; + } +} + + +bool save_gridstars( + const std::string& fname, + const std::string& group, + const std::string& dset, + std::vector >& fit_centers, + std::vector& fit_icovs) +{ + // Number of stars to save + uint32_t n_stars = fit_centers.size(); + if(n_stars == 0) { + std::cerr << "! No stars to write." << std::endl; + return false; + } + + // # of covariance matrices should match # of stars + assert(fit_icovs.size() == 3 * n_stars); + + // Open up file and create group + H5::Exception::dontPrint(); + + std::unique_ptr file = H5Utils::openFile(fname); + if(!file) { return false; } + + std::unique_ptr gp = H5Utils::openGroup(*file, group); + if(!gp) { return false; } + + // Determine maximum number of Gaussians for one star + uint32_t n_gaussians = 0; + for(auto& v : fit_centers) { + if(v.size() > n_gaussians) { + n_gaussians = v.size(); + } + } + + // Datatype + H5::CompType dtype(sizeof(TDMESaveData)); + dtype.insertMember("dm", HOFFSET(TDMESaveData, dm), H5::PredType::NATIVE_FLOAT); + dtype.insertMember("E", HOFFSET(TDMESaveData, E), H5::PredType::NATIVE_FLOAT); + dtype.insertMember("Mr", HOFFSET(TDMESaveData, Mr), H5::PredType::NATIVE_FLOAT); + dtype.insertMember("FeH", HOFFSET(TDMESaveData, FeH), H5::PredType::NATIVE_FLOAT); + dtype.insertMember("ln_likelihood", HOFFSET(TDMESaveData, ln_likelihood), H5::PredType::NATIVE_FLOAT); + dtype.insertMember("ln_prior", HOFFSET(TDMESaveData, ln_prior), H5::PredType::NATIVE_FLOAT); + + // Dataspace + hsize_t dim[2] = {n_stars, n_gaussians}; + H5::DataSpace dspace(2, &(dim[0])); + + // Property List + H5::DSetCreatPropList plist; + + // Target chunk size of 1 MB + int64_t target_size = 1024*1024; + int64_t size_per_star = n_gaussians * sizeof(TDMESaveData); + hsize_t n_stars_chunk = target_size / size_per_star; + if(n_stars_chunk < 1) { + n_stars_chunk = 1; + } else if(n_stars_chunk > n_stars) { + n_stars_chunk = n_stars; + } + hsize_t chunk[2] = {n_stars_chunk, n_gaussians}; + plist.setChunk(2, &(chunk[0])); + + plist.setDeflate(3); // DEFLATE compression level (min=0, max=9) + + // Dataset + H5::DataSet dataset = gp->createDataSet(dset, dtype, dspace, plist); + + // Copy data into one array + TDMESaveData* data = new TDMESaveData[n_stars*n_gaussians]; + for(int i=0; idm = 0.; + d->E = 0.; + d->ln_likelihood = -std::numeric_limits::infinity(); + d->ln_prior = -std::numeric_limits::infinity(); + } + } + + // Write dataset + dataset.write(data, dtype); + + // Write stellar covariances + std::stringstream dset_cov; + dset_cov << dset << "_icov"; + + //std::cout << "dset_cov = " << dset_cov.str() << std::endl; + + hsize_t dim_cov[2] = {n_stars, 3}; // (dm,dm), (dm,E), (E,E) + H5::DataSpace dspace_cov(2, &(dim_cov[0])); + + H5::DSetCreatPropList plist_cov; + int64_t size_per_star_cov = dim_cov[1] * sizeof(float); + hsize_t n_stars_chunk_cov = target_size / size_per_star_cov; + if(n_stars_chunk_cov < 1) { + n_stars_chunk_cov = 1; + } else if(n_stars_chunk_cov > n_stars) { + n_stars_chunk_cov = n_stars; + } + hsize_t chunk_cov[2] = {n_stars_chunk_cov, dim_cov[1]}; + plist_cov.setChunk(2, &(chunk_cov[0])); + plist_cov.setDeflate(3); // DEFLATE compression level (min=0, max=9) + //std::cout << "chunk length: " << n_stars_chunk_cov << std::endl; + + //std::cout << "Creating dataset_cov" << std::endl; + + H5::DataSet dataset_cov = gp->createDataSet( + dset_cov.str(), + H5::PredType::NATIVE_FLOAT, + dspace_cov, + plist_cov); + + //std::cout << "Writing dataset_cov" << std::endl; + + dataset_cov.write(fit_icovs.data(), H5::PredType::NATIVE_FLOAT); + + // Attribute noting meaning of inverse cov. matrix entries + //std::cout << "Closing file" << std::endl; + file->close(); + + //std::cout << "Adding attribute" << std::endl; + std::stringstream dset_cov_fullpath; + dset_cov_fullpath << group << "/" << dset_cov.str(); + //std::cout << "Writing attribute to " << dset_cov_fullpath.str() + // << std::endl; + std::string attr_name = "entries"; + std::string attr_value = "dd, dE, EE"; + H5Utils::add_watermark( + fname, + dset_cov_fullpath.str(), + attr_name, + attr_value + ); + std::cout << "Done." << std::endl; + return true; +} diff --git a/src/star_exact.h b/src/star_exact.h new file mode 100644 index 0000000..89536f3 --- /dev/null +++ b/src/star_exact.h @@ -0,0 +1,92 @@ + +#ifndef _STAR_EXACT_H__ +#define _STAR_EXACT_H__ + + +#include +#include +#include +#include +#include +#include + +#include + +#include "model.h" +#include "data.h" +#include "chain.h" +#include "los_sampler.h" + + +class LinearFitParams { +public: + LinearFitParams(unsigned int n_dim); + + Eigen::VectorXd mean; + Eigen::Matrix inv_cov; + double chi2; + +private: + unsigned int _n_dim; +}; + + +std::shared_ptr star_max_likelihood( + TSED& mags_model, + TStellarData::TMagnitudes& mags_obs, + TExtinctionModel& ext_model, + double RV=3.1); + + +void star_covariance(TStellarData::TMagnitudes& mags_obs, + TExtinctionModel& ext_model, + double& inv_cov_00, double& inv_cov_01, double& inv_cov_11, + double RV=3.1); + +void star_max_likelihood(TSED& mags_model, TStellarData::TMagnitudes& mags_obs, + TExtinctionModel& ext_model, + double inv_cov_00, double inv_cov_01, double inv_cov_11, + double& mu, double& E, double& chi2, + double RV=3.1); + +struct TDMESaveData { + float dm; + float E; + float Mr; + float FeH; + float ln_likelihood; + float ln_prior; +}; + +double integrate_ML_solution( + TStellarModel& stellar_model, + TGalacticLOSModel& los_model, + TStellarData::TMagnitudes& mags_obs, + TExtinctionModel& ext_model, + TImgStack& img_stack, + unsigned int img_idx, + bool save_gaussians, + std::vector& fit_centers, + std::vector& fit_icov, + bool use_priors, + bool use_gaia, + double RV, int verbosity); + +void grid_eval_stars(TGalacticLOSModel& los_model, TExtinctionModel& ext_model, + TStellarModel& stellar_model, TStellarData& stellar_data, + TEBVSmoothing& EBV_smoothing, + TImgStack& img_stack, std::vector& chi2, + bool save_surfs, bool save_gaussians, + std::string out_fname, + bool use_priors, bool use_gaia, + double RV, int verbosity); + +bool save_gridstars( + const std::string& fname, + const std::string& group, + const std::string& dset, + std::vector >& fit_centers, + std::vector& fit_icovs); + + +#endif // _STAR_EXACT_H__