Skip to content

Commit

Permalink
Merge pull request #334 from lanl/jmm/plugin
Browse files Browse the repository at this point in the history
Add plugin infrastructure
  • Loading branch information
Yurlungur authored Jan 25, 2024
2 parents f097b44 + 463f92d commit 2a66420
Show file tree
Hide file tree
Showing 17 changed files with 717 additions and 56 deletions.
1 change: 1 addition & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ jobs:
-DSINGULARITY_USE_HELMHOLTZ=ON \
-DSINGULARITY_TEST_HELMHOLTZ=ON \
-DSINGULARITY_FORCE_SUBMODULE_MODE=ON \
-DSINGULARITY_PLUGINS=$(pwd)/../example/plugin \
..
#-DSINGULARITY_TEST_PYTHON=ON \
#-DSINGULARITY_TEST_STELLAR_COLLAPSE=ON \
Expand Down
4 changes: 2 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@

### Fixed (Repair bugs, etc)
- [[PR335]](https://github.com/lanl/singularity-eos/pull/335) Fix missing hermite.hpp in CMake install required for Helmholtz EOS
### Added (new features/APIs/variables/...)
- [[PR331]](https://github.com/lanl/singularity-eos/pull/331) Included code and documentation for a full, temperature consistent, Mie-Gruneisen EOS based on a linear Us-up relation.

### Added (new features/APIs/variables/...)
- [[PR334]](https://github.com/lanl/singularity-eos/pull/334) Include plugins infrastructure
- [[PR331]](https://github.com/lanl/singularity-eos/pull/331) Included code and documentation for a full, temperature consistent, Mie-Gruneisen EOS based on a linear Us-up relation.
- [[PR326]](https://github.com/lanl/singularity-eos/pull/326) Document how to do a release

### Changed (changing behavior/API/variables/...)
Expand Down
39 changes: 29 additions & 10 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,11 @@ option(SINGULARITY_FORCE_SUBMODULE_MODE "Submodule mode" OFF)
option(SINGULARITY_PATCH_MPARK_VARIANT
"Apply GPU patch to mpark-variant submodule" ON)

# Plugins
set(SINGULARITY_PLUGINS "" CACHE STRING "List of paths to plugin directories")
set(SINGULARITY_VARIANT "singularity-eos/eos/default_variant.hpp" CACHE STRING
"The include path for the file containing the definition of singularity::EOS.")

# ------------------------------------------------------------------------------#
# singularity-eos Library
# ------------------------------------------------------------------------------#
Expand Down Expand Up @@ -359,27 +364,34 @@ if(SINGULARITY_BUILD_TESTS)
endif()
endif()

# ##########################OLD
# ------------------------------------------------------------------------------#
# Plugin infrastructure
# ------------------------------------------------------------------------------#
include(cmake/plugins.cmake)
set(PLUGIN_BUILD_ROOT "${CMAKE_CURRENT_BINARY_DIR}/plugins")

# ------------------------------------------------------------------------------#
# singularity-eos library
# ------------------------------------------------------------------------------#

# this subdirectory populates `EOS_HEADERS/EOS_SRCS` NOTE: these include path
# Here we populate `EOS_HEADERS/EOS_SRCS` NOTE: these include path
# prefixes of subdirectories on files (e.g. eos/eos.hpp) see
# singularity-eos/CMakeLists.txt

add_subdirectory(singularity-eos)

foreach(_header ${EOS_HEADERS})
list(APPEND _install_headers ${_header})
list(APPEND _headers singularity-eos/${_header})
foreach(_plugin ${SINGULARITY_PLUGINS})
message(STATUS "Adding plugin ${_plugin}...")
get_filename_component(BINDIR_LOC ${_plugin} NAME)
add_subdirectory(${_plugin} ${PLUGIN_BUILD_ROOT}/${BINDIR_LOC})
endforeach()

foreach(_src ${EOS_SRCS})
list(APPEND _srcs singularity-eos/${_src})
endforeach()
# TODO(JMM): Kind of nice to have?
get_property(eos_headers GLOBAL PROPERTY EOS_HEADERS)
get_property(eos_srcs GLOBAL PROPERTY EOS_SRCS)
message(VERBOSE "EOS Headers:\n\t${eos_headers}")
message(VERBOSE "EOS Sources:\n\t${eos_srcs}")

target_sources(singularity-eos PRIVATE ${_srcs} ${_headers})
target_sources(singularity-eos PRIVATE ${eos_srcs} ${eos_headers})

if(SINGULARITY_USE_FORTRAN)
# Turn on preprocessor for fortran files
Expand All @@ -396,6 +408,13 @@ endif() # SINGULARITY_USE_FORTRAN
target_include_directories(
singularity-eos PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
$<INSTALL_INTERFACE:include>)
target_include_directories(
singularity-eos PUBLIC $<BUILD_INTERFACE:${CMAKE_BINARY_DIR}/generated>)

get_property(plugin_include_paths GLOBAL PROPERTY PLUGIN_INCLUDE_PATHS)
foreach(path ${plugin_include_paths})
target_include_directories(singularity-eos PUBLIC $<BUILD_INTERFACE:${path}>)
endforeach()

# plug in collected includes/libs/definitions

Expand Down
16 changes: 12 additions & 4 deletions cmake/install.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -70,12 +70,20 @@ install(
# ----------------------------------------------------------------------------#

# install singularity-eos headers
foreach(file ${_install_headers})
get_filename_component(DIR ${file} DIRECTORY)
install(FILES singularity-eos/${file}
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/singularity-eos/${DIR})
get_property(install_headers GLOBAL PROPERTY _install_headers)
list(LENGTH install_headers length)
math(EXPR max_index "${length} - 1")
foreach(index RANGE ${max_index})
list(GET eos_headers ${index} src)
list(GET install_headers ${index} dst)
get_filename_component(DIR ${dst} DIRECTORY)
install(FILES ${src} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${DIR})
endforeach() # file

# Special sauce so generated file has proper include path
install(FILES ${CMAKE_BINARY_DIR}/generated/singularity-eos/eos/eos.hpp
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/singularity-eos/eos)

# install the fortran modules NB: cmake doesn't provide a clean way to handle
if(SINGULARITY_USE_FORTRAN)
install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/fortran/
Expand Down
64 changes: 64 additions & 0 deletions cmake/plugins.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
#------------------------------------------------------------------------------#
# © 2024. Triad National Security, LLC. All rights reserved. This
# program was produced under U.S. Government contract 89233218CNA000001
# for Los Alamos National Laboratory (LANL), which is operated by Triad
# National Security, LLC for the U.S. Department of Energy/National
# Nuclear Security Administration. All rights in the program are
# reserved by Triad National Security, LLC, and the U.S. Department of
# Energy/National Nuclear Security Administration. The Government is
# granted for itself and others acting on its behalf a nonexclusive,
# paid-up, irrevocable worldwide license in this material to reproduce,
# prepare derivative works, distribute copies to the public, perform
# publicly and display publicly, and to permit others to do so.
#------------------------------------------------------------------------------#

set_property(GLOBAL PROPERTY EOS_HEADERS "")
set_property(GLOBAL PROPERTY _install_headers "")
function(register_headers)
set(keyword_args PLUGIN)
cmake_parse_arguments(ARG "" "${keyword_args}" "" ${ARGN})
set(variadic_args ${ARG_UNPARSED_ARGUMENTS})

get_property(eos_headers GLOBAL PROPERTY EOS_HEADERS)
get_property(install_headers GLOBAL PROPERTY _install_headers)

foreach(arg IN LISTS variadic_args)
file(RELATIVE_PATH relative_path ${CMAKE_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR})
if (ARG_PLUGIN)
list(APPEND eos_headers ${relative_path}/${ARG_PLUGIN}/${arg})
list(APPEND install_headers ${ARG_PLUGIN}/${arg})
else()
list(APPEND eos_headers ${relative_path}/${arg})
list(APPEND install_headers ${relative_path}/${arg})
endif()
endforeach()
set_property(GLOBAL PROPERTY EOS_HEADERS "${eos_headers}")
set_property(GLOBAL PROPERTY _install_headers "${install_headers}")
endfunction()

set_property(GLOBAL PROPERTY EOS_SRCS "")
function(register_srcs)
get_property(eos_srcs GLOBAL PROPERTY EOS_SRCS)
foreach(arg IN LISTS ARGN)
file(RELATIVE_PATH relative_path ${CMAKE_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR})
list(APPEND eos_srcs ${relative_path}/${arg})
endforeach()
set_property(GLOBAL PROPERTY EOS_SRCS "${eos_srcs}")
endfunction()

set(PLUGIN_TESTS "")
set_property(GLOBAL PROPERTY PLUGIN_TESTS "")
function(register_tests)
get_property(plugin_tests GLOBAL PROPERTY PLUGIN_TESTS)
foreach(arg IN LISTS ARGN)
list(APPEND plugin_tests ${CMAKE_CURRENT_SOURCE_DIR}/${arg})
endforeach()
set_property(GLOBAL PROPERTY PLUGIN_TESTS "${plugin_tests}")
endfunction()

set_property(GLOBAL PROPERTY PLUGIN_INCLUDE_PATHS "")
macro(export_plugin)
get_property(plugin_include_paths GLOBAL PROPERTY PLUGIN_INCLUDE_PATHS)
list(APPEND plugin_include_paths ${CMAKE_CURRENT_SOURCE_DIR})
set_property(GLOBAL PROPERTY PLUGIN_INCLUDE_PATHS "${plugin_include_paths}")
endmacro()
1 change: 1 addition & 0 deletions doc/sphinx/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ Documentation approved for unlimited release. LA-UR-21-31131.
src/using-eos
src/models
src/modifiers
src/customization
src/using-closures
src/python
src/contributing
Expand Down
143 changes: 143 additions & 0 deletions doc/sphinx/src/customization
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
.. _customization:

Customizing ``singularity-eos``
================================

Custom Variant
---------------

If you would like to create your own custom variant with additional
models (or a subset of models), you may do so by using the
``eos_variant`` class. For example,

.. code-block:: cpp

#include <singularity-eos/eos.hpp>
using namespace singularity;

using MyEOS_t = eos_variant<IdealGas, Gruneisen>;

This will create a new type, ``MyEOS_t`` which contains only the
``IdealGas`` and ``Gruneisen`` classes. (All of these live under the
``singularity`` namespace.)

Plugins
--------

.. warning::

Plugins are currently an experimental feature. Use at your own risk.

``singularity-eos`` is also extensible via a plugins
infrastructure. Via plugins, you may define additional equations of
state and have them automatically built, tested, and installed by the
library. You may even include them in the default ``singularity-eos``
variant type.

.. note::

We note that a downstream code built on ``singularity-eos`` may
have no need of a plugin infrastructure, as you can write your own
EOS models and and choose your own ``Variant`` type for your code
all within your context. Plugins are a way of adding arbitrary code
to ``singularity-eos`` that you may wish to share accross multiple
downstream codes (for example).

The easiest way to explain how to add a plugin is probably by
example. In the ``example`` directory of the ``singularity-eos``
source tree is a ``plugin`` subdirectory containing an example
plugin. The example plugin contains an implementation of astrophysical
dust. In this context dust is a pressure-less gas. We implement this
with an equation of state that always returns zero pressure, but has a
temperature and specific heat.

The plugin directory contains a ``CMakeLists.txt`` file (described
more below) and a subdirectory named ``dust``, which contains the
source code. The name of the subdirectory will specify how it may be
included in code referencing the plugin. For example, to include the
dust equation of state explicitly, a user of this plugin would use the
include statement

.. code-block:: cpp

#include <dust/dust.hpp>

You may have as many subdirectories as you like, one for each "include
path" you want to make available.

The plugin directory also contains a ``tst`` directory, which contains
an implementation file ``tst/test_dust.cpp``, which contains several
Catch2 tests. See the contribution guide for a longer discussion of
the ``singularity-eos`` testing infrastructure.

The ``CMakeLists.txt`` file registers the plugin with the build system
via several custom ``cmake`` functions provided by
``singularity-eos``. To register a header file (and most files in
``singularity-eos`` should be header files) we use (for example)

.. code-block::

register_headers(PLUGIN dust dust.hpp dust_variant.hpp)

This specifies that the ``dust`` subdirectory contains two header
files that the infrastructure should know about: ``dust.hpp`` and
``dust_variant.hpp``. One such line is required for every additional
top-level subdirectory of the plugin directory.

The dust plugin has no source files, however, these may be registered with

.. code-block::

register_srcs(src1 src2 src3 ...)

note that ``register_srcs`` does **not** take the ``PLUGIN path``
syntax. Simply use the relative path from the ``CMakeLists.txt`` file to the source
file.

To register the test, we call

.. code-block::

register_tests(tst/test_dust.cpp)

As with source files, do not use the ``PLUGIN PATH`` syntax. Just use
the relative path to the ``cpp`` file containing the tests.

Finally, call

.. code-block::

export_plugin()

to ensure the registrations described above are pushed to "top level"
scope of the build system.

To use a plugin so-defined, you must tell the build system that it
exists at configure time. To do so, call

.. code-block::

-DSINGULARITY_PLUGINS="/path/to/my/plugin1;/path/to/my/plugin2"

where the above defines a semicolon-separated list of paths to plugin
directories. For example, to register the dust plugin:

.. code-block::

-DSINGULARITY_PLUGINS=/path/to/singularity-eos/example/plugin

Re-defining the default variant
--------------------------------

The ``dust`` plugin also contains a file ``dust/dust_variant.hpp``,
which contains a definition of the ``EOS`` type (i.e., a variant) but
with the dust equation of state included. To tell the infrastructure
to use **this** variant rather than the default, specify the "include
path" at configure time. For example:

.. code-block::

-DSINGULARITY_VARIANT="dust/dust_variant.hpp"

There may only be *one* definition for the ``SINGULARITY_VARIANT`` at
a time, so only specify for one of your plugins, if you have multiple.
2 changes: 1 addition & 1 deletion doc/sphinx/src/getting-started.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ At it's most basic, you can download and compile ``singularity-eos`` with:
cd singularity-eos
mkdir bin
cd bin
cmake -DSINGULARITY_FORCE_SUBMODULEMODE=ON -DSINGULARITY_USE_FORTRAN=OFF ..
cmake -DSINGULARITY_FORCE_SUBMODULE_MODE=ON -DSINGULARITY_USE_FORTRAN=OFF ..
make -j
make install # optional: install into directory defined via CMAKE_INSTALL_PREFIX
Expand Down
22 changes: 22 additions & 0 deletions example/plugin/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#------------------------------------------------------------------------------#
# © 2024. Triad National Security, LLC. All rights reserved. This
# program was produced under U.S. Government contract 89233218CNA000001
# for Los Alamos National Laboratory (LANL), which is operated by Triad
# National Security, LLC for the U.S. Department of Energy/National
# Nuclear Security Administration. All rights in the program are
# reserved by Triad National Security, LLC, and the U.S. Department of
# Energy/National Nuclear Security Administration. The Government is
# granted for itself and others acting on its behalf a nonexclusive,
# paid-up, irrevocable worldwide license in this material to reproduce,
# prepare derivative works, distribute copies to the public, perform
# publicly and display publicly, and to permit others to do so.
#------------------------------------------------------------------------------#

# Add the header file to the list of headers
register_headers(PLUGIN dust dust.hpp dust_variant.hpp)

# Register this test to be built in the test suite
register_tests(tst/test_dust.cpp)

# Export lists to parent scope
export_plugin()
Loading

0 comments on commit 2a66420

Please sign in to comment.