Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add option to build without MFEM #26

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
128 changes: 76 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")
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 @@ -165,12 +166,35 @@ pybind11_add_module(_pylibROM
bindings/pylibROM/utils/pyHDFDatabase.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 *
15 changes: 15 additions & 0 deletions bindings/pylibROM/pylibROM.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
#include <pybind11/pybind11.h>

#include "CAROM_config.h"
#include "pylibROM_config.h"

// check that libROM has MFEM if pylibROM is using MFEM
#ifdef PYLIBROM_HAS_MFEM
// temporarily disabled until libROM upstream adds this option
// #ifndef CAROM_HAS_MFEM
// #error "libROM was not compiled with MFEM support"
// #endif
#endif

namespace py = pybind11;

//linalg
Expand Down Expand Up @@ -47,10 +58,12 @@ void init_Database(pybind11::module_ &m);
void init_HDFDatabase(pybind11::module_ &m);
void init_CSVDatabase(pybind11::module_ &m);

#ifdef PYLIBROM_HAS_MFEM
//mfem
void init_mfem_Utilities(pybind11::module_ &m);
void init_mfem_PointwiseSnapshot(pybind11::module_ &m);
void init_mfem_SampleMesh(pybind11::module_ &m);
#endif

PYBIND11_MODULE(_pylibROM, m) {
py::module utils = m.def_submodule("utils");
Expand Down Expand Up @@ -97,10 +110,12 @@ PYBIND11_MODULE(_pylibROM, m) {
init_STSampling(hyperreduction);
init_Utilities(hyperreduction);

#ifdef PYLIBROM_HAS_MFEM
py::module mfem = m.def_submodule("mfem");
init_mfem_Utilities(mfem);
init_mfem_PointwiseSnapshot(mfem);
init_mfem_SampleMesh(mfem);
#endif

// py::module python_utils = m.def_submodule("python_utils");
}
Expand Down
6 changes: 6 additions & 0 deletions bindings/pylibROM/pylibROM_config.h.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#ifndef PYLIBROM_CONFIG_H_
#define PYLIBROM_CONFIG_H_

#cmakedefine PYLIBROM_HAS_MFEM

#endif
73 changes: 63 additions & 10 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,30 @@
# It recommends using "--config-settings", though there is no clear documentation about this.
# For now, we enforce to use the versions < 23.3.0.
import pkg_resources
pkg_resources.require(['pip < 23.3.0'])
#pkg_resources.require(['pip < 23.3.0'])

from setuptools import Extension, setup, find_packages
from setuptools.command.build_ext import build_ext
from setuptools.command.install import install as _install

# Take the global option for pre-installed librom directory.
librom_dir = None
install_scalapack = False
use_mfem = True
# TODO: fix this.. passing options through pip to setuptools with PEP517 is not working
for arg in sys.argv:
if (arg[:13] == "--librom_dir="):
if (arg[:13] == "--librom_dir=" or arg[:13] == "--librom-dir="):
librom_dir = arg[13:]
sys.argv.remove(arg)
if "--install_scalapack" in sys.argv:
install_scalapack = True
sys.argv.remove("--install_scalapack")
if (arg[:19] == "--install_scalapack"):
install_scalapack = True
sys.argv.remove(arg)
if (arg[:9] == "--no-mfem"):
use_mfem = False
sys.argv.remove(arg)
if (arg[:10] == "--use-mfem"):
use_mfem = True
sys.argv.remove(arg)

# Convert distutils Windows platform specifiers to CMake -A arguments
PLAT_TO_CMAKE = {
Expand All @@ -41,6 +50,38 @@ def __init__(self, name: str, sourcedir: str = "") -> None:
self.sourcedir = os.fspath(Path(sourcedir).resolve())


class InstallBuild(_install):

user_options = _install.user_options + [
("librom-dir=", None, "Path to libROM root directory. If specified, pylibROM will use this instead of compiling its own libROM."),
("install-scalapack", None, "Enables SCALAPACK when building libROM."),
("use-mfem", None, "Compile pylibROM with MFEM enabled."),
("no-mfem", None, "Compile pylibROM without MFEM.")
]

negative_opt = dict(_install.negative_opt)
negative_opt.update({"no-mfem" : "use-mfem"})

def run(self):
_install.run(self)


def initialize_options(self):
_install.initialize_options(self)
self.librom_dir = None
self.install_scalapack = False
self.use_mfem = True


def finalize_options(self):
global librom_dir, install_scalapack, use_mfem
librom_dir = self.librom_dir
install_scalapack = self.install_scalapack
use_mfem = self.use_mfem

_install.finalize_options(self)


class CMakeBuild(build_ext):
def build_extension(self, ext: CMakeExtension) -> None:
# Must be in this form due to bug in .resolve() only fixed in Python 3.10+
Expand All @@ -57,15 +98,16 @@ def build_extension(self, ext: CMakeExtension) -> None:
# Can be set with Conda-Build, for example.
cmake_generator = os.environ.get("CMAKE_GENERATOR", "")

global librom_dir, install_scalapack
global librom_dir, install_scalapack, use_mfem
cmake_args = []
if (librom_dir is None):
librom_dir = os.path.dirname(os.path.realpath(__file__))
librom_dir += "/extern/libROM"
librom_dir += "/extern/libROM/"
print("Installing libROM library: %s" % librom_dir)

librom_cmd = "cd %s && ./scripts/compile.sh -m -g -t ./cmake/toolchains/simple.cmake" % librom_dir
librom_cmd = "cd %s && ./scripts/compile.sh -t ./cmake/toolchains/simple.cmake" % librom_dir
if (install_scalapack): librom_cmd += " -s"
if (use_mfem): librom_cmd += " -m -g"
print("libROM installation command: %s" % librom_cmd)
subprocess.run(
librom_cmd, shell=True, check=True
Expand All @@ -74,6 +116,8 @@ def build_extension(self, ext: CMakeExtension) -> None:
print("Using pre-installed libROM library: %s" % librom_dir)
cmake_args += [f"-DLIBROM_DIR=%s" % librom_dir]

cmake_args += ["-DUSE_MFEM={:s}".format('ON' if use_mfem else 'OFF')]

# Set Python_EXECUTABLE instead if you use PYBIND11_FINDPYTHON
# EXAMPLE_VERSION_INFO shows you how to pass a value into the C++ code
# from Python.
Expand Down Expand Up @@ -152,10 +196,18 @@ def build_extension(self, ext: CMakeExtension) -> None:
["cmake", ext.sourcedir, *cmake_args], cwd=build_temp, check=True
)
subprocess.run(
["cmake", "--build", ".", *build_args], cwd=build_temp, check=True
["cmake", "--build", ".", "-j 8", "-v", *build_args], cwd=build_temp, check=True
)


def initialize_options(self):
build_ext.initialize_options(self)


def finalize_options(self):
build_ext.finalize_options(self)


# The information here can also be placed in setup.cfg - better separation of
# logic and declaration, and simpler if you include description/version in a file.
setup(
Expand All @@ -165,12 +217,13 @@ def build_extension(self, ext: CMakeExtension) -> None:
# author_email="[email protected]",
description="Python Interface for LLNL libROM",
long_description="",
packages=find_packages(where='bindings'),
packages=find_packages(where='bindings', exclude=['pylibROM.mfem'] if use_mfem == False else ['']),
package_dir={"":"bindings"},
# packages=['bindings/pylibROM'],
ext_modules=[CMakeExtension("_pylibROM")],
cmdclass={
"build_ext": CMakeBuild,
"install": InstallBuild
},
zip_safe=False,
extras_require={"test": ["pytest>=6.0"]},
Expand Down
Loading