Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
9c62b7a
Add option to build without MFEM
ckendrick May 30, 2024
15b6dc2
CMake adjustments and add config header for pylibROM
ckendrick May 30, 2024
e74465c
Disable libROM mfem check temporarily
ckendrick May 31, 2024
fe34c0c
Update setup.py install with options
ckendrick Jun 11, 2024
9b4fa81
Update bindings to remove time intervals
ckendrick May 7, 2024
404f5f9
Update BasisReader tests
ckendrick May 7, 2024
e82e5df
Update pyMatrix bindings for orthogonalize double pass
ckendrick May 7, 2024
04482fc
Update Database with MPIO
ckendrick Aug 1, 2024
af4eeb5
Add MPI comm to pydatabase functions
ckendrick Aug 1, 2024
ea80cb8
Test for HDFDatabaseMPIO
ckendrick Aug 8, 2024
bbf3b70
Update bindings for QR factors
ckendrick Aug 15, 2024
074298d
Update Matrix tests, remove old orthogonalize test
ckendrick Aug 21, 2024
c39542a
Skip STSampling tests for now
ckendrick Aug 29, 2024
806cec3
Update libROM submodule
ckendrick Sep 5, 2024
59c29bf
Revert to manual parsing due to pip issues
ckendrick Sep 26, 2024
1794614
Update pymfem and libROM versions in dockerfiles
ckendrick Sep 26, 2024
9500640
Use mpi hdf5 in dockerfile, add lapack to mfem
ckendrick Nov 19, 2024
c2d8490
Update build settings and fix MPIO when hdf5 is serial
ckendrick Dec 9, 2024
5879272
Fix binding functions for Database classes
ckendrick Dec 11, 2024
c2f0f89
Move librom_dir to dash for setuptools parsing
ckendrick Dec 11, 2024
ed41f30
Add import test to CI and add search path for libparmetis
ckendrick Dec 17, 2024
38e9858
Update pip install command and add pyproject.toml
ckendrick Dec 17, 2024
e98b521
Fix import when using cmake
ckendrick Dec 17, 2024
8f7fcd2
Fix path to use CI workspace
ckendrick Dec 17, 2024
0468b35
Fix scipy import in NNLS test for older versions
ckendrick Dec 30, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,10 @@ jobs:
git submodule status
- name: build
run: |
pip install ./ --global-option="--librom_dir=/env/dependencies/libROM"
pip install -v --user -C"--build-option=install" -C"--build-option=--librom-dir=/env/dependencies/libROM" -C"--build-option=-v" ./
- name: check install
run: |
python3 -c "import pylibROM"
- name: test
run: |
cd tests
Expand Down Expand Up @@ -106,6 +109,10 @@ jobs:
cd build
cmake .. -DLIBROM_DIR=/env/dependencies/libROM
make
- name: check install
run: |
cd build
python3 -c "import _pylibROM"
- name: test
run: |
cd tests
Expand Down Expand Up @@ -168,8 +175,13 @@ jobs:
- name: build
run: |
pip install ./
- name: check install
run: |
export LD_LIBRARY_PATH=$GITHUB_WORKSPACE/extern/libROM/dependencies/parmetis-4.0.3/build/lib/libparmetis/:$GITHUB_WORKSPACE/extern/libROM/dependencies/parmetis-4.0.3/build/lib/libmetis/
python3 -c "import pylibROM"
- name: test
run: |
export LD_LIBRARY_PATH=$GITHUB_WORKSPACE/extern/libROM/dependencies/parmetis-4.0.3/build/lib/libparmetis/:$GITHUB_WORKSPACE/extern/libROM/dependencies/parmetis-4.0.3/build/lib/libmetis/
cd tests
echo run pyVector unit test
pytest test_pyVector.py --verbose
Expand Down
129 changes: 77 additions & 52 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ project(_pylibROM)
set(CMAKE_BUILD_TYPE Debug)
set(PYBIND11_FINDPYTHON ON)

option (USE_MFEM "Build pylibROM with MFEM" OFF)

#=================== ScaLAPACK (optional) ==================
option(BUILD_SCALAPACK "Build static ScaLAPACK for libROM" OFF)

Expand Down Expand Up @@ -50,14 +52,18 @@ if (BUILD_LIBROM)
# )
# add_custom_target(RUN_LIBROM_BUILD ALL DEPENDS LIBROM_BUILD)

ExternalProject_Add(
libROM
SOURCE_DIR ${LIBROM_SCRIPTS_DIR}
CONFIGURE_COMMAND ""
BINARY_DIR ${LIBROM_DIR}
BUILD_COMMAND ${LIBROM_SCRIPTS_DIR}/compile.sh -m -g -t ${LIBROM_DIR}/cmake/toolchains/simple.cmake
INSTALL_COMMAND ""
)
set(LIBROM_BUILD_CMD "${LIBROM_SCRIPTS_DIR}/compile.sh -t ${LIBROM_DIR}/cmake/toolchains/simple.cmake" CACHE STRING "Command used to build libROM and dependencies")
if (USE_MFEM)
set(LIBROM_BUILD_CMD "${LIBROM_BUILD_CMD} -m -g -l")
endif()
# ExternalProject_Add(
# libROM
# SOURCE_DIR ${LIBROM_SCRIPTS_DIR}
# CONFIGURE_COMMAND ""
# BINARY_DIR ${LIBROM_DIR}
# BUILD_COMMAND ${LIBROM_BUILD_CMD}
# INSTALL_COMMAND ""
# )
message("Building libROM dependency...")
endif(BUILD_LIBROM)

Expand All @@ -72,63 +78,58 @@ execute_process(COMMAND python3 -c "import mpi4py; print(mpi4py.get_include())"
# # TODO(kevin): We do not bind mfem-related functions until we figure out how to type-cast SWIG Object.
# # Until then, mfem-related functions need to be re-implemented on python-end, using PyMFEM.

find_library(MFEM mfem
"$ENV{MFEM_DIR}/lib"
"$ENV{MFEM_DIR}"
"${LIBROM_DIR}/dependencies/mfem")
find_library(HYPRE HYPRE
"$ENV{HYPRE_DIR}/lib"
"${LIBROM_DIR}/dependencies/hypre/src/hypre/lib")
find_library(PARMETIS parmetis
"$ENV{PARMETIS_DIR}/lib"
"$ENV{PARMETIS_DIR}/build/lib/libparmetis"
"${LIBROM_DIR}/dependencies/parmetis-4.0.3/build/lib/libparmetis")
find_library(METIS metis
"$ENV{METIS_DIR}/lib"
"$ENV{PARMETIS_DIR}/build/lib/libmetis"
"${LIBROM_DIR}/dependencies/parmetis-4.0.3/build/lib/libmetis")
find_path(MFEM_INCLUDES mfem.hpp
"$ENV{MFEM_DIR}/include"
"$ENV{MFEM_DIR}"
"${LIBROM_DIR}/dependencies/mfem")
find_path(HYPRE_INCLUDES HYPRE.h
"$ENV{HYPRE_DIR}/include"
"${LIBROM_DIR}/dependencies/hypre/src/hypre/include")
find_path(PARMETIS_INCLUDES metis.h
"$ENV{PARMETIS_DIR}/metis/include"
"${LIBROM_DIR}/dependencies/parmetis-4.0.3/metis/include")

if (USE_MFEM)
find_library(MFEM mfem
"$ENV{MFEM_DIR}/lib"
"$ENV{MFEM_DIR}"
"${LIBROM_DIR}/dependencies/mfem")
find_library(HYPRE HYPRE
"$ENV{HYPRE_DIR}/lib"
"${LIBROM_DIR}/dependencies/hypre/src/hypre/lib")
find_library(PARMETIS parmetis
"$ENV{PARMETIS_DIR}/lib"
"$ENV{PARMETIS_DIR}/build/lib/libparmetis"
"${LIBROM_DIR}/dependencies/parmetis-4.0.3/build/lib/libparmetis")
find_library(METIS metis
"$ENV{METIS_DIR}/lib"
"$ENV{PARMETIS_DIR}/build/lib/libmetis"
"${LIBROM_DIR}/dependencies/parmetis-4.0.3/build/lib/libmetis")
find_path(MFEM_INCLUDES mfem.hpp
"$ENV{MFEM_DIR}/include"
"$ENV{MFEM_DIR}"
"${LIBROM_DIR}/dependencies/mfem")
find_path(HYPRE_INCLUDES HYPRE.h
"$ENV{HYPRE_DIR}/include"
"${LIBROM_DIR}/dependencies/hypre/src/hypre/include")
find_path(PARMETIS_INCLUDES metis.h
"$ENV{PARMETIS_DIR}/metis/include"
"${LIBROM_DIR}/dependencies/parmetis-4.0.3/metis/include")
set(PYLIBROM_HAS_MFEM 1)
endif()
#===================== pylibROM =============================


set(CMAKE_CXX_STANDARD 14)

find_package(MPI REQUIRED)

set(SOURCE_DIR "bindings/pylibROM")
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/bindings/pylibROM/pylibROM_config.h.in
${CMAKE_CURRENT_SOURCE_DIR}/bindings/pylibROM/pylibROM_config.h)

set(SOURCE_DIR "bindings/pylibROM")
include_directories(
${SOURCE_DIR}
${LIBROM_INCLUDE_DIR}
${MPI_INCLUDE_PATH}
${MPI4PY}
${HDF5_C_INCLUDE_DIRS}
${MFEM_INCLUDES}
${HYPRE_INCLUDES}
${PARMETIS_INCLUDES}
${MFEM_C_INCLUDE_DIRS}
)
link_libraries(
${HDF5_LIBRARIES}
${MFEM}
${HYPRE}
${PARMETIS}
${METIS}
)
link_libraries(${HDF5_LIBRARIES})

add_subdirectory("extern/pybind11")

pybind11_add_module(_pylibROM
bindings/pylibROM/pylibROM.cpp
set(PYLIBROM_SOURCES
bindings/pylibROM/pylibROM.cpp

bindings/pylibROM/linalg/pyMatrix.cpp
bindings/pylibROM/linalg/pyVector.cpp
Expand Down Expand Up @@ -163,14 +164,38 @@ pybind11_add_module(_pylibROM
bindings/pylibROM/utils/pyDatabase.hpp
bindings/pylibROM/utils/pyDatabase.cpp
bindings/pylibROM/utils/pyHDFDatabase.cpp
bindings/pylibROM/utils/pyHDFDatabaseMPIO.cpp
bindings/pylibROM/utils/pyCSVDatabase.cpp

bindings/pylibROM/mfem/pyUtilities.cpp
bindings/pylibROM/mfem/pyPointwiseSnapshot.cpp
bindings/pylibROM/mfem/pySampleMesh.cpp

bindings/pylibROM/python_utils/cpp_utils.hpp
)

if (USE_MFEM)
set(PYLIBROM_SOURCES ${PYLIBROM_SOURCES}
bindings/pylibROM/mfem/pyUtilities.cpp
bindings/pylibROM/mfem/pyPointwiseSnapshot.cpp
bindings/pylibROM/mfem/pySampleMesh.cpp)
endif()

pybind11_add_module(_pylibROM ${PYLIBROM_SOURCES})
message("building pylibROM...")

if (USE_MFEM)
target_include_directories(
_pylibROM
PUBLIC
${MFEM_INCLUDES}
${HYPRE_INCLUDES}
${PARMETIS_INCLUDES}
${MFEM_C_INCLUDE_DIRS})

target_link_libraries(
_pylibROM
PUBLIC
${MFEM}
${HYPRE}
${PARMETIS}
${METIS})
endif()

target_link_libraries(_pylibROM PRIVATE ROM)
12 changes: 11 additions & 1 deletion bindings/pylibROM/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,14 @@
# either define/import the python routine in this file.
# This will combine both c++ bindings/pure python routines into this module.

from _pylibROM import *
from _pylibROM.algo import *
from _pylibROM.hyperreduction import *
from _pylibROM.linalg import *

try:
import _pylibROM.mfem
from _pylibROM.mfem import *
except:
pass

from _pylibROM.utils import *
8 changes: 3 additions & 5 deletions bindings/pylibROM/linalg/pyBasisGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ void init_BasisGenerator(pybind11::module_ &m) {
)
.def("isNextSample", (bool (BasisGenerator::*)(double)) &BasisGenerator::isNextSample)
.def("updateRightSV", (bool (BasisGenerator::*)()) &BasisGenerator::updateRightSV)
.def("takeSample", [](BasisGenerator& self, py::array_t<double> &u_in, double time, double dt, bool add_without_increase = false) {
return self.takeSample(getVectorPointer(u_in), time, dt, add_without_increase);
}, py::arg("u_in"), py::arg("time"), py::arg("dt"), py::arg("add_without_increase") = false)
.def("takeSample", [](BasisGenerator& self, py::array_t<double> &u_in, bool add_without_increase = false) {
return self.takeSample(getVectorPointer(u_in), add_without_increase);
}, py::arg("u_in"), py::arg("add_without_increase") = false)
.def("endSamples", &BasisGenerator::endSamples, py::arg("kind") = "basis")
.def("writeSnapshot", (void (BasisGenerator::*)()) &BasisGenerator::writeSnapshot)
.def("loadSamples", (void (BasisGenerator::*)(const std::string&, const std::string&, int, Database::formats)) &BasisGenerator::loadSamples,
Expand All @@ -39,8 +39,6 @@ void init_BasisGenerator(pybind11::module_ &m) {
.def("getTemporalBasis", (const Matrix* (BasisGenerator::*)()) &BasisGenerator::getTemporalBasis,py::return_value_policy::reference)
.def("getSingularValues", (const Vector* (BasisGenerator::*)()) &BasisGenerator::getSingularValues,py::return_value_policy::reference)
.def("getSnapshotMatrix", (const Matrix* (BasisGenerator::*)()) &BasisGenerator::getSnapshotMatrix,py::return_value_policy::reference)
.def("getNumBasisTimeIntervals", (int (BasisGenerator::*)() const) &BasisGenerator::getNumBasisTimeIntervals)
.def("getBasisIntervalStartTime", (double (BasisGenerator::*)(int) const) &BasisGenerator::getBasisIntervalStartTime, py::arg("which_interval"))
.def("getNumSamples",(int (BasisGenerator::*)() const) &BasisGenerator::getNumSamples)
.def("__del__", [](BasisGenerator& self) { self.~BasisGenerator(); }); // Destructor

Expand Down
54 changes: 19 additions & 35 deletions bindings/pylibROM/linalg/pyBasisReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,54 +12,38 @@ using namespace CAROM;

void init_BasisReader(pybind11::module_ &m) {
py::class_<BasisReader>(m, "BasisReader")
.def(py::init<const std::string&, Database::formats>(),
.def(py::init<const std::string&, Database::formats, const int>(),
py::arg("base_file_name"),
py::arg("file_format") = Database::formats::HDF5
py::arg("file_format") = Database::formats::HDF5,
py::arg("dim") = -1
)
.def("isNewBasis",(bool (BasisReader::*)(double)) &BasisReader::isNewBasis,
py::arg("time"))
.def("getSpatialBasis",(Matrix* (BasisReader::*)(double)) &BasisReader::getSpatialBasis,
py::arg("time"))
.def("getSpatialBasis",(Matrix* (BasisReader::*)(double,int)) &BasisReader::getSpatialBasis,
py::arg("time"),
.def("getSpatialBasis",(Matrix* (BasisReader::*)()) &BasisReader::getSpatialBasis)
.def("getSpatialBasis",(Matrix* (BasisReader::*)(int)) &BasisReader::getSpatialBasis,
py::arg("n"))
.def("getSpatialBasis",(Matrix* (BasisReader::*)(double,int,int)) &BasisReader::getSpatialBasis,
py::arg("time"),
.def("getSpatialBasis",(Matrix* (BasisReader::*)(int,int)) &BasisReader::getSpatialBasis,
py::arg("start_col"),
py::arg("end_col"))
.def("getSpatialBasis",(Matrix* (BasisReader::*)(double,double)) &BasisReader::getSpatialBasis,
py::arg("time"),
.def("getSpatialBasis",(Matrix* (BasisReader::*)(double)) &BasisReader::getSpatialBasis,
py::arg("ef").noconvert())
.def("getTemporalBasis",(Matrix* (BasisReader::*)(double)) &BasisReader::getTemporalBasis,
py::arg("time"))
.def("getTemporalBasis",(Matrix* (BasisReader::*)(double,int)) &BasisReader::getTemporalBasis,
py::arg("time"),
.def("getTemporalBasis",(Matrix* (BasisReader::*)()) &BasisReader::getTemporalBasis)
.def("getTemporalBasis",(Matrix* (BasisReader::*)(int)) &BasisReader::getTemporalBasis,
py::arg("n"))
.def("getTemporalBasis",(Matrix* (BasisReader::*)(double,int,int)) &BasisReader::getTemporalBasis,
py::arg("time"),
.def("getTemporalBasis",(Matrix* (BasisReader::*)(int,int)) &BasisReader::getTemporalBasis,
py::arg("start_col"),
py::arg("end_col"))
.def("getTemporalBasis",(Matrix* (BasisReader::*)(double,double)) &BasisReader::getTemporalBasis,
py::arg("time"),
.def("getTemporalBasis",(Matrix* (BasisReader::*)(double)) &BasisReader::getTemporalBasis,
py::arg("ef").noconvert())
.def("getSingularValues",(Vector* (BasisReader::*)()) &BasisReader::getSingularValues)
.def("getSingularValues",(Vector* (BasisReader::*)(double)) &BasisReader::getSingularValues,
py::arg("time"))
.def("getSingularValues",(Vector* (BasisReader::*)(double,double)) &BasisReader::getSingularValues,
py::arg("time"),
py::arg("ef"))
.def("getDim", (int (BasisReader::*)(const std::string,double)) &BasisReader::getDim,
py::arg("kind"),
py::arg("time"))
.def("getNumSamples", (int (BasisReader::*)(const std::string,double)) &BasisReader::getNumSamples,
py::arg("kind"),
py::arg("time"))
.def("getSnapshotMatrix",(Matrix* (BasisReader::*)(double)) &BasisReader::getSnapshotMatrix,
py::arg("time"))
.def("getSnapshotMatrix",(Matrix* (BasisReader::*)(double,int)) &BasisReader::getSnapshotMatrix,
py::arg("time"),
.def("getDim", (int (BasisReader::*)(const std::string)) &BasisReader::getDim,
py::arg("kind"))
.def("getNumSamples", (int (BasisReader::*)(const std::string)) &BasisReader::getNumSamples,
py::arg("kind"))
.def("getSnapshotMatrix",(Matrix* (BasisReader::*)()) &BasisReader::getSnapshotMatrix)
.def("getSnapshotMatrix",(Matrix* (BasisReader::*)(int)) &BasisReader::getSnapshotMatrix,
py::arg("n"))
.def("getSnapshotMatrix",(Matrix* (BasisReader::*)(double,int,int)) &BasisReader::getSnapshotMatrix,
py::arg("time"),
.def("getSnapshotMatrix",(Matrix* (BasisReader::*)(int,int)) &BasisReader::getSnapshotMatrix,
py::arg("start_col"),
py::arg("end_col"))
.def("__del__", [](BasisReader& self) { self.~BasisReader(); }); // Destructor
Expand Down
9 changes: 7 additions & 2 deletions bindings/pylibROM/linalg/pyMatrix.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,11 @@ void init_matrix(pybind11::module_ &m) {

.def("transposePseudoinverse",(void (Matrix::*)()) &Matrix::transposePseudoinverse)

.def("qr_factorize",(Matrix* (Matrix::*)() const) &Matrix::qr_factorize,py::return_value_policy::take_ownership)
.def("qr_factorize", [](const Matrix& self) -> std::vector<std::unique_ptr<Matrix>> {
std::vector<std::unique_ptr<Matrix>> qr;
self.qr_factorize(qr);
return qr;
})

// TODO (kevin): due to the difference between python and c++, technically we should not take
// row_pivot and row_pivot_owner as input parameters, just returning them in the end as outputs.
Expand All @@ -189,7 +193,8 @@ void init_matrix(pybind11::module_ &m) {
return std::make_tuple(row_pivot, row_pivot_owner);
})

.def("orthogonalize", (void (Matrix::*)()) &Matrix::orthogonalize)
.def("orthogonalize", (void (Matrix::*)(bool, double)) &Matrix::orthogonalize, py::arg("double_pass") = false, py::arg("zero_tol") = 1.0e-15)
.def("orthogonalize_last", (void (Matrix::*)(int, bool, double)) &Matrix::orthogonalize_last, py::arg("ncols") = -1, py::arg("double_pass") = false, py::arg("zero_tol") = 1.0e-15)

.def("item", (const double& (Matrix::*)(int, int) const) &Matrix::item)
.def("__getitem__", [](Matrix& self, int row, int col) {
Expand Down
6 changes: 3 additions & 3 deletions bindings/pylibROM/linalg/pyOptions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,9 @@ using namespace CAROM;
void init_Options(pybind11::module_ &m) {

py::class_<Options>(m, "Options")
.def(py::init<int, int, int, bool, bool>(), py::arg("dim_"), py::arg("samples_per_time_interval_"),py::arg("max_time_intervals_") = -1,py::arg("update_right_SV_") = false, py::arg("write_snapshots_") = false)
.def(py::init<int, int, bool, bool>(), py::arg("dim_"), py::arg("max_num_samples_"),py::arg("update_right_SV_") = false, py::arg("write_snapshots_") = false)
.def_readwrite("dim", &Options::dim)
.def_readwrite("samples_per_time_interval", &Options::samples_per_time_interval)
.def_readwrite("max_time_intervals", &Options::max_time_intervals)
.def_readwrite("max_num_samples", &Options::max_num_samples)
.def_readwrite("update_right_SV", &Options::update_right_SV)
.def_readwrite("write_snapshots", &Options::write_snapshots)
.def_readwrite("max_basis_dimension", &Options::max_basis_dimension)
Expand All @@ -33,6 +32,7 @@ void init_Options(pybind11::module_ &m) {
.def_readwrite("min_sampling_time_step_scale", &Options::min_sampling_time_step_scale)
.def_readwrite("sampling_time_step_scale", &Options::sampling_time_step_scale)
.def_readwrite("max_sampling_time_step_scale", &Options::max_sampling_time_step_scale)
.def_readwrite("static_svd_preserve_snapshot", &Options::static_svd_preserve_snapshot)
.def("setMaxBasisDimension", &Options::setMaxBasisDimension, py::arg("max_basis_dimension_"))
.def("setSingularValueTol", &Options::setSingularValueTol, py::arg("singular_value_tol_"))
.def("setDebugMode", &Options::setDebugMode, py::arg("debug_algorithm_"))
Expand Down
Loading
Loading