├── .github └── workflows │ ├── ci.yml │ ├── docker_base.yml │ └── docker_librom.yml ├── .gitignore ├── .gitmodules ├── CMakeLists.txt ├── LICENSE ├── README.md ├── bindings ├── .bash_history └── pylibROM │ ├── __init__.py │ ├── algo │ ├── __init__.py │ ├── greedy │ │ ├── __init__.py │ │ ├── pyGreedyCustomSampler.cpp │ │ ├── pyGreedyRandomSampler.cpp │ │ └── pyGreedySampler.cpp │ ├── manifold_interp │ │ ├── __init__.py │ │ ├── pyInterpolator.cpp │ │ ├── pyMatrixInterpolator.cpp │ │ └── pyVectorInterpolator.cpp │ ├── pyAdaptiveDMD.cpp │ ├── pyDMD.cpp │ ├── pyNonuniformDMD.cpp │ └── pyParametricDMD.cpp │ ├── hyperreduction │ ├── __init__.py │ ├── pyDEIM.cpp │ ├── pyGNAT.cpp │ ├── pyQDEIM.cpp │ ├── pySTSampling.cpp │ ├── pyS_OPT.cpp │ └── pyUtilities.cpp │ ├── linalg │ ├── __init__.py │ ├── pyBasisGenerator.cpp │ ├── pyBasisReader.cpp │ ├── pyBasisWriter.cpp │ ├── pyMatrix.cpp │ ├── pyNNLS.cpp │ ├── pyOptions.cpp │ ├── pyVector.cpp │ └── svd │ │ ├── __init__.py │ │ ├── pyIncrementalSVD.cpp │ │ ├── pySVD.cpp │ │ └── pyStaticSVD.cpp │ ├── mfem │ ├── PointwiseSnapshot.py │ ├── Utilities.py │ ├── __init__.py │ ├── pyPointwiseSnapshot.cpp │ ├── pySampleMesh.cpp │ └── pyUtilities.cpp │ ├── pylibROM.cpp │ ├── pylibROM_config.h.in │ ├── python_utils │ ├── StopWatch.py │ ├── __init__.py │ └── cpp_utils.hpp │ └── utils │ ├── __init__.py │ ├── mpi_utils.cpp │ ├── mpicomm.hpp │ ├── pyCSVDatabase.cpp │ ├── pyDatabase.cpp │ ├── pyDatabase.hpp │ ├── pyHDFDatabase.cpp │ └── pyHDFDatabaseMPIO.cpp ├── docker ├── baseline │ └── Dockerfile ├── jupyter │ └── Dockerfile └── librom │ └── Dockerfile ├── examples ├── data │ ├── beam-hex-nurbs.mesh │ ├── beam-quad.mesh │ ├── beam-tri.mesh │ ├── inline-quad.mesh │ ├── periodic-hexagon.mesh │ ├── periodic-square.mesh │ └── star.mesh ├── dmd │ ├── dg_advection.py │ ├── dg_euler.ipynb │ ├── dg_euler.py │ ├── dg_euler_common.py │ ├── heat_conduction_csv.sh │ ├── heat_conduction_hdf.sh │ ├── local_tw_csv.py │ ├── nonlinear_elasticity.ipynb │ ├── nonlinear_elasticity.py │ ├── parametric_heat_conduction.ipynb │ ├── parametric_heat_conduction.py │ ├── parametric_tw_csv.py │ ├── wave_equation.ipynb │ └── wave_equation.py └── prom │ ├── dg_advection_global_rom.py │ ├── dg_advection_local_rom_matrix_interp.py │ ├── linear_elasticity_global_rom.py │ ├── nonlinear_elasticity_global_rom.ipynb │ ├── nonlinear_elasticity_global_rom.py │ ├── poisson_global_rom.ipynb │ └── poisson_global_rom.py ├── extern ├── PyMFEM.setup.py └── librom_scalapack.sh ├── pyproject.toml ├── setup.py └── tests ├── test_Options.py ├── test_Vector.py ├── test_pyBasisGenerator.py ├── test_pyBasisReader.py ├── test_pyBasisWriter.py ├── test_pyDEIM.py ├── test_pyDMD.py ├── test_pyGNAT.py ├── test_pyGreedyCustomSampler.py ├── test_pyHDFDatabaseMPIO.py ├── test_pyIncrementalSVD.py ├── test_pyMatrix.py ├── test_pyNNLS.py ├── test_pyOptions.py ├── test_pyQDEIM.py ├── test_pyQR.py ├── test_pySTSampling.py ├── test_pySVD.py ├── test_pyS_OPT.py ├── test_pyStaticSVD.py ├── test_pyUtilities.py └── test_pyVector.py /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: 3 | workflow_dispatch: {} 4 | pull_request: 5 | types: [opened, labeled, synchronize] 6 | branches: 7 | - main 8 | # push: 9 | # branches: 10 | # - main 11 | 12 | jobs: 13 | docker-librom-image: 14 | uses: ./.github/workflows/docker_librom.yml 15 | docker-base-image: 16 | uses: ./.github/workflows/docker_base.yml 17 | pip-with-librom: 18 | runs-on: ubuntu-latest 19 | needs: [docker-librom-image] 20 | container: 21 | image: ghcr.io/llnl/pylibrom/pylibrom_env:latest 22 | options: --user 1001 --privileged 23 | volumes: 24 | - /mnt:/mnt 25 | steps: 26 | - name: Cancel previous runs 27 | uses: styfle/cancel-workflow-action@0.11.0 28 | with: 29 | access_token: ${{ github.token }} 30 | - name: Set Swap Space 31 | uses: pierotofy/set-swap-space@master 32 | with: 33 | swap-size-gb: 10 34 | - name: Check out pylibROM 35 | uses: actions/checkout@v1 36 | with: 37 | submodules: 'true' 38 | - name: Git Submodules status 39 | run: | 40 | git submodule status 41 | - name: build 42 | run: | 43 | pip install -v --user -C"--build-option=install" -C"--build-option=--librom-dir=/env/dependencies/libROM" -C"--build-option=-v" ./ 44 | - name: check install 45 | run: | 46 | python3 -c "import pylibROM" 47 | - name: test 48 | run: | 49 | cd tests 50 | echo run pyVector unit test 51 | pytest test_pyVector.py --verbose 52 | echo run pyMatrix unit test 53 | pytest test_pyMatrix.py --verbose 54 | mpirun -n 2 pytest test_pyMatrix.py --verbose 55 | echo run pyOptions unit test 56 | pytest test_pyOptions.py --verbose 57 | echo run pySVD unit test 58 | pytest test_pySVD.py --verbose 59 | echo run pyStaticSVD unit test 60 | pytest test_pyStaticSVD.py --verbose 61 | echo run pyIncrementalSVD unit test 62 | pytest test_pyIncrementalSVD.py --verbose 63 | echo run pyBasisGenerator unit test 64 | pytest test_pyBasisGenerator.py --verbose 65 | echo run pyBasisReader unit test 66 | pytest test_pyBasisReader.py --verbose 67 | echo run pyBasisWriter unit test 68 | pytest test_pyBasisWriter.py --verbose 69 | echo run pyDMD unit test 70 | pytest test_pyDMD.py --verbose 71 | mpirun -n 2 pytest test_pyDMD.py --verbose 72 | echo run pyDEIM unit test 73 | pytest test_pyDEIM.py --verbose 74 | echo run pyGNAT unit test 75 | pytest test_pyGNAT.py --verbose 76 | echo run pyQDEIM unit test 77 | pytest test_pyQDEIM.py --verbose 78 | echo run pyS_OPT unit test 79 | pytest test_pyS_OPT.py --verbose 80 | echo run pyUtilities unit test 81 | pytest test_pyUtilities.py --verbose 82 | cmake-with-librom: 83 | runs-on: ubuntu-latest 84 | needs: [docker-librom-image] 85 | container: 86 | image: ghcr.io/llnl/pylibrom/pylibrom_env:latest 87 | options: --user 1001 --privileged 88 | volumes: 89 | - /mnt:/mnt 90 | steps: 91 | - name: Cancel previous runs 92 | uses: styfle/cancel-workflow-action@0.11.0 93 | with: 94 | access_token: ${{ github.token }} 95 | - name: Set Swap Space 96 | uses: pierotofy/set-swap-space@master 97 | with: 98 | swap-size-gb: 10 99 | - name: Check out pylibROM 100 | uses: actions/checkout@v1 101 | with: 102 | submodules: 'true' 103 | - name: Git Submodules status 104 | run: | 105 | git submodule status 106 | - name: build 107 | run: | 108 | mkdir build 109 | cd build 110 | cmake .. -DLIBROM_DIR=/env/dependencies/libROM 111 | make 112 | - name: check install 113 | run: | 114 | cd build 115 | python3 -c "import _pylibROM" 116 | - name: test 117 | run: | 118 | cd tests 119 | echo run pyVector unit test 120 | pytest test_pyVector.py --verbose 121 | echo run pyMatrix unit test 122 | pytest test_pyMatrix.py --verbose 123 | mpirun -n 2 pytest test_pyMatrix.py --verbose 124 | echo run pyOptions unit test 125 | pytest test_pyOptions.py --verbose 126 | echo run pySVD unit test 127 | pytest test_pySVD.py --verbose 128 | echo run pyStaticSVD unit test 129 | pytest test_pyStaticSVD.py --verbose 130 | echo run pyIncrementalSVD unit test 131 | pytest test_pyIncrementalSVD.py --verbose 132 | echo run pyBasisGenerator unit test 133 | pytest test_pyBasisGenerator.py --verbose 134 | echo run pyBasisReader unit test 135 | pytest test_pyBasisReader.py --verbose 136 | echo run pyBasisWriter unit test 137 | pytest test_pyBasisWriter.py --verbose 138 | echo run pyDMD unit test 139 | pytest test_pyDMD.py --verbose 140 | mpirun -n 2 pytest test_pyDMD.py --verbose 141 | echo run pyDEIM unit test 142 | pytest test_pyDEIM.py --verbose 143 | echo run pyGNAT unit test 144 | pytest test_pyGNAT.py --verbose 145 | echo run pyQDEIM unit test 146 | pytest test_pyQDEIM.py --verbose 147 | echo run pyS_OPT unit test 148 | pytest test_pyS_OPT.py --verbose 149 | echo run pyUtilities unit test 150 | pytest test_pyUtilities.py --verbose 151 | baseline: 152 | runs-on: ubuntu-latest 153 | needs: [docker-base-image] 154 | container: 155 | image: ghcr.io/llnl/pylibrom/pylibrom_env_base:latest 156 | options: --user 1001 --privileged 157 | volumes: 158 | - /mnt:/mnt 159 | steps: 160 | - name: Cancel previous runs 161 | uses: styfle/cancel-workflow-action@0.11.0 162 | with: 163 | access_token: ${{ github.token }} 164 | - name: Set Swap Space 165 | uses: pierotofy/set-swap-space@master 166 | with: 167 | swap-size-gb: 10 168 | - name: Check out pylibROM 169 | uses: actions/checkout@v1 170 | with: 171 | submodules: 'true' 172 | - name: Git Submodules status 173 | run: | 174 | git submodule status 175 | - name: build 176 | run: | 177 | pip install ./ 178 | - name: check install 179 | run: | 180 | 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/ 181 | python3 -c "import pylibROM" 182 | - name: test 183 | run: | 184 | 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/ 185 | cd tests 186 | echo run pyVector unit test 187 | pytest test_pyVector.py --verbose 188 | echo run pyMatrix unit test 189 | pytest test_pyMatrix.py --verbose 190 | mpirun -n 2 pytest test_pyMatrix.py --verbose 191 | echo run pyOptions unit test 192 | pytest test_pyOptions.py --verbose 193 | echo run pySVD unit test 194 | pytest test_pySVD.py --verbose 195 | echo run pyStaticSVD unit test 196 | pytest test_pyStaticSVD.py --verbose 197 | echo run pyIncrementalSVD unit test 198 | pytest test_pyIncrementalSVD.py --verbose 199 | echo run pyBasisGenerator unit test 200 | pytest test_pyBasisGenerator.py --verbose 201 | echo run pyBasisReader unit test 202 | pytest test_pyBasisReader.py --verbose 203 | echo run pyBasisWriter unit test 204 | pytest test_pyBasisWriter.py --verbose 205 | echo run pyDMD unit test 206 | pytest test_pyDMD.py --verbose 207 | mpirun -n 2 pytest test_pyDMD.py --verbose 208 | echo run pyDEIM unit test 209 | pytest test_pyDEIM.py --verbose 210 | echo run pyGNAT unit test 211 | pytest test_pyGNAT.py --verbose 212 | echo run pyQDEIM unit test 213 | pytest test_pyQDEIM.py --verbose 214 | echo run pyS_OPT unit test 215 | pytest test_pyS_OPT.py --verbose 216 | echo run pyUtilities unit test 217 | pytest test_pyUtilities.py --verbose 218 | 219 | -------------------------------------------------------------------------------- /.github/workflows/docker_base.yml: -------------------------------------------------------------------------------- 1 | name: docker-image 2 | on: 3 | workflow_call: 4 | 5 | env: 6 | REGISTRY: ghcr.io 7 | # github.repository as / 8 | IMAGE_NAME: llnl/pylibROM/pylibROM_env_base 9 | DOCKERPATH: docker/baseline 10 | 11 | jobs: 12 | docker-ci: 13 | runs-on: ubuntu-latest 14 | name: "docker env" 15 | steps: 16 | - uses: actions/checkout@v3 17 | with: 18 | fetch-depth: 0 19 | - uses: Ana06/get-changed-files@v2.2.0 20 | id: files 21 | - name: DockerPATH configuration 22 | run: echo "DOCKERPATH=$DOCKERPATH" 23 | - name: DockerPATH - check if files in docker path changed 24 | if: contains(steps.files.outputs.all,env.DOCKERPATH) || contains(steps.files.outputs.all,'docker_base.yml') 25 | run: | 26 | echo "CI container needs rebuilding..." 27 | echo "CI_NEEDS_REBUILD=true" >> $GITHUB_ENV 28 | - name: Log into registry ${{ env.REGISTRY }} 29 | if: env.CI_NEEDS_REBUILD 30 | uses: docker/login-action@v2 31 | with: 32 | registry: ${{ env.REGISTRY }} 33 | username: ${{ github.actor }} 34 | password: ${{ secrets.GITHUB_TOKEN }} 35 | - name: Extract metadata (tags, labels) for Docker 36 | id: meta 37 | if: env.CI_NEEDS_REBUILD 38 | uses: docker/metadata-action@v4 39 | with: 40 | images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} 41 | tags: type=sha 42 | flavor: latest=true 43 | - name: Build Container motd 44 | if: env.CI_NEEDS_REBUILD 45 | run: | 46 | echo "#!/bin/bash" > ${{env.DOCKERPATH}}/motd.sh 47 | echo "echo --------------------------" >> ${{env.DOCKERPATH}}/motd.sh 48 | echo "echo pylibrom_env/CI Development Container" >> ${{env.DOCKERPATH}}/motd.sh 49 | echo "echo \"Revision: `echo ${GITHUB_SHA} | cut -c1-8`\"" >> ${{env.DOCKERPATH}}/motd.sh 50 | echo "echo --------------------------" >> ${{env.DOCKERPATH}}/motd.sh 51 | chmod 755 ${{env.DOCKERPATH}}/motd.sh 52 | cat ${{env.DOCKERPATH}}/motd.sh 53 | - name: Docker Image - Build and push 54 | if: env.CI_NEEDS_REBUILD 55 | uses: docker/build-push-action@v3 56 | with: 57 | push: true 58 | context: ${{ env.DOCKERPATH }} 59 | tags: ${{ steps.meta.outputs.tags }} 60 | -------------------------------------------------------------------------------- /.github/workflows/docker_librom.yml: -------------------------------------------------------------------------------- 1 | name: docker-image 2 | on: 3 | workflow_call: 4 | 5 | env: 6 | REGISTRY: ghcr.io 7 | # github.repository as / 8 | IMAGE_NAME: llnl/pylibROM/pylibROM_env 9 | DOCKERPATH: docker/librom 10 | 11 | jobs: 12 | docker-ci: 13 | runs-on: ubuntu-latest 14 | name: "docker env" 15 | steps: 16 | - uses: actions/checkout@v3 17 | with: 18 | fetch-depth: 0 19 | - uses: Ana06/get-changed-files@v2.2.0 20 | id: files 21 | - name: DockerPATH configuration 22 | run: echo "DOCKERPATH=$DOCKERPATH" 23 | - name: DockerPATH - check if files in docker path changed 24 | if: contains(steps.files.outputs.all,env.DOCKERPATH) || contains(steps.files.outputs.all,'docker_librom.yml') 25 | run: | 26 | echo "CI container needs rebuilding..." 27 | echo "CI_NEEDS_REBUILD=true" >> $GITHUB_ENV 28 | - name: Log into registry ${{ env.REGISTRY }} 29 | if: env.CI_NEEDS_REBUILD 30 | uses: docker/login-action@v2 31 | with: 32 | registry: ${{ env.REGISTRY }} 33 | username: ${{ github.actor }} 34 | password: ${{ secrets.GITHUB_TOKEN }} 35 | - name: Extract metadata (tags, labels) for Docker 36 | id: meta 37 | if: env.CI_NEEDS_REBUILD 38 | uses: docker/metadata-action@v4 39 | with: 40 | images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} 41 | tags: type=sha 42 | flavor: latest=true 43 | - name: Build Container motd 44 | if: env.CI_NEEDS_REBUILD 45 | run: | 46 | echo "#!/bin/bash" > ${{env.DOCKERPATH}}/motd.sh 47 | echo "echo --------------------------" >> ${{env.DOCKERPATH}}/motd.sh 48 | echo "echo pylibrom_env/CI Development Container" >> ${{env.DOCKERPATH}}/motd.sh 49 | echo "echo \"Revision: `echo ${GITHUB_SHA} | cut -c1-8`\"" >> ${{env.DOCKERPATH}}/motd.sh 50 | echo "echo --------------------------" >> ${{env.DOCKERPATH}}/motd.sh 51 | chmod 755 ${{env.DOCKERPATH}}/motd.sh 52 | cat ${{env.DOCKERPATH}}/motd.sh 53 | - name: Docker Image - Build and push 54 | if: env.CI_NEEDS_REBUILD 55 | uses: docker/build-push-action@v3 56 | with: 57 | push: true 58 | context: ${{ env.DOCKERPATH }} 59 | tags: ${{ steps.meta.outputs.tags }} 60 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .gitignore 2 | build 3 | .git/ 4 | .github 5 | *.egg-info 6 | *.mfem_root 7 | *.gf 8 | examples/dmd/DMD_Wave_Equation_* 9 | examples/dmd/Wave_Equation_* 10 | examples/dmd/wave_equation.mesh 11 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "extern/pybind11"] 2 | path = extern/pybind11 3 | url = ../../pybind/pybind11 4 | branch = stable 5 | [submodule "extern/libROM"] 6 | path = extern/libROM 7 | url = https://github.com/LLNL/libROM.git -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.12) 2 | 3 | project(_pylibROM) 4 | 5 | set(CMAKE_BUILD_TYPE Debug) 6 | set(PYBIND11_FINDPYTHON ON) 7 | 8 | option (USE_MFEM "Build pylibROM with MFEM" OFF) 9 | 10 | #=================== ScaLAPACK (optional) ================== 11 | option(BUILD_SCALAPACK "Build static ScaLAPACK for libROM" OFF) 12 | 13 | if (BUILD_SCALAPACK) 14 | set(WORK_DIR ${CMAKE_CURRENT_SOURCE_DIR}/extern) 15 | add_custom_command( 16 | OUTPUT SLPK_BUILD 17 | WORKING_DIRECTORY ${WORK_DIR} 18 | COMMAND ${WORK_DIR}/librom_scalapack.sh 19 | COMMENT "Building Static ScaLAPACK..." 20 | ) 21 | add_custom_target(RUN_SLPK_BUILD ALL DEPENDS SLPK_BUILD) 22 | endif(BUILD_SCALAPACK) 23 | 24 | # HDF5 25 | find_package(HDF5 1.8.0 REQUIRED) 26 | 27 | #=================== libROM ================================ 28 | 29 | #It is tedious to build libROM. option to not build 30 | set(LIBROM_DIR "" CACHE STRING "absolute path to the pre-installed libROM") 31 | 32 | set(BUILD_LIBROM OFF) 33 | if (NOT LIBROM_DIR) 34 | set(LIBROM_DIR ${CMAKE_CURRENT_SOURCE_DIR}/extern/libROM) 35 | set(LIBROM_SCRIPTS_DIR ${LIBROM_DIR}/scripts) 36 | set(BUILD_LIBROM ON) 37 | endif() 38 | 39 | include(ExternalProject) 40 | 41 | include(CMakePrintHelpers) 42 | cmake_print_variables(LIBROM_DIR) 43 | cmake_print_variables(LIBROM_SCRIPTS_DIR) 44 | 45 | if (BUILD_LIBROM) 46 | # add_custom_command( 47 | # OUTPUT LIBROM_BUILD 48 | # WORKING_DIRECTORY ${LIBROM_DIR} 49 | # COMMAND ${LIBROM_SCRIPTS_DIR}/compile.sh 50 | # ARGS -m -t ${LIBROM_DIR}/cmake/toolchains/simple.cmake 51 | # COMMENT "Building libROM..." 52 | # ) 53 | # add_custom_target(RUN_LIBROM_BUILD ALL DEPENDS LIBROM_BUILD) 54 | 55 | 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") 56 | if (USE_MFEM) 57 | set(LIBROM_BUILD_CMD "${LIBROM_BUILD_CMD} -m -g -l") 58 | endif() 59 | # ExternalProject_Add( 60 | # libROM 61 | # SOURCE_DIR ${LIBROM_SCRIPTS_DIR} 62 | # CONFIGURE_COMMAND "" 63 | # BINARY_DIR ${LIBROM_DIR} 64 | # BUILD_COMMAND ${LIBROM_BUILD_CMD} 65 | # INSTALL_COMMAND "" 66 | # ) 67 | message("Building libROM dependency...") 68 | endif(BUILD_LIBROM) 69 | 70 | #setup external dependency build and link paths for libROM 71 | set(LIBROM_INCLUDE_DIR ${LIBROM_DIR}/lib) 72 | link_directories(${LIBROM_DIR}/build/lib) #this hack is the best way for non-cmake since FetchContent will not work for compile.sh 73 | 74 | #include mpi4py directory 75 | execute_process(COMMAND python3 -c "import mpi4py; print(mpi4py.get_include())" OUTPUT_VARIABLE MPI4PY) 76 | 77 | # # MFEM is required. 78 | # # TODO(kevin): We do not bind mfem-related functions until we figure out how to type-cast SWIG Object. 79 | # # Until then, mfem-related functions need to be re-implemented on python-end, using PyMFEM. 80 | 81 | if (USE_MFEM) 82 | find_library(MFEM mfem 83 | "$ENV{MFEM_DIR}/lib" 84 | "$ENV{MFEM_DIR}" 85 | "${LIBROM_DIR}/dependencies/mfem") 86 | find_library(HYPRE HYPRE 87 | "$ENV{HYPRE_DIR}/lib" 88 | "${LIBROM_DIR}/dependencies/hypre/src/hypre/lib") 89 | find_library(PARMETIS parmetis 90 | "$ENV{PARMETIS_DIR}/lib" 91 | "$ENV{PARMETIS_DIR}/build/lib/libparmetis" 92 | "${LIBROM_DIR}/dependencies/parmetis-4.0.3/build/lib/libparmetis") 93 | find_library(METIS metis 94 | "$ENV{METIS_DIR}/lib" 95 | "$ENV{PARMETIS_DIR}/build/lib/libmetis" 96 | "${LIBROM_DIR}/dependencies/parmetis-4.0.3/build/lib/libmetis") 97 | find_path(MFEM_INCLUDES mfem.hpp 98 | "$ENV{MFEM_DIR}/include" 99 | "$ENV{MFEM_DIR}" 100 | "${LIBROM_DIR}/dependencies/mfem") 101 | find_path(HYPRE_INCLUDES HYPRE.h 102 | "$ENV{HYPRE_DIR}/include" 103 | "${LIBROM_DIR}/dependencies/hypre/src/hypre/include") 104 | find_path(PARMETIS_INCLUDES metis.h 105 | "$ENV{PARMETIS_DIR}/metis/include" 106 | "${LIBROM_DIR}/dependencies/parmetis-4.0.3/metis/include") 107 | set(PYLIBROM_HAS_MFEM 1) 108 | endif() 109 | #===================== pylibROM ============================= 110 | 111 | 112 | set(CMAKE_CXX_STANDARD 14) 113 | 114 | find_package(MPI REQUIRED) 115 | 116 | configure_file(${CMAKE_CURRENT_SOURCE_DIR}/bindings/pylibROM/pylibROM_config.h.in 117 | ${CMAKE_CURRENT_SOURCE_DIR}/bindings/pylibROM/pylibROM_config.h) 118 | 119 | set(SOURCE_DIR "bindings/pylibROM") 120 | include_directories( 121 | ${SOURCE_DIR} 122 | ${LIBROM_INCLUDE_DIR} 123 | ${MPI_INCLUDE_PATH} 124 | ${MPI4PY} 125 | ${HDF5_C_INCLUDE_DIRS} 126 | ) 127 | link_libraries(${HDF5_LIBRARIES}) 128 | 129 | add_subdirectory("extern/pybind11") 130 | 131 | set(PYLIBROM_SOURCES 132 | bindings/pylibROM/pylibROM.cpp 133 | 134 | bindings/pylibROM/linalg/pyMatrix.cpp 135 | bindings/pylibROM/linalg/pyVector.cpp 136 | bindings/pylibROM/linalg/pyBasisGenerator.cpp 137 | bindings/pylibROM/linalg/pyBasisReader.cpp 138 | bindings/pylibROM/linalg/pyBasisWriter.cpp 139 | bindings/pylibROM/linalg/pyOptions.cpp 140 | bindings/pylibROM/linalg/pyNNLS.cpp 141 | bindings/pylibROM/linalg/svd/pySVD.cpp 142 | bindings/pylibROM/linalg/svd/pyStaticSVD.cpp 143 | bindings/pylibROM/linalg/svd/pyIncrementalSVD.cpp 144 | 145 | bindings/pylibROM/algo/pyDMD.cpp 146 | bindings/pylibROM/algo/pyParametricDMD.cpp 147 | bindings/pylibROM/algo/pyNonuniformDMD.cpp 148 | bindings/pylibROM/algo/pyAdaptiveDMD.cpp 149 | bindings/pylibROM/algo/greedy/pyGreedySampler.cpp 150 | bindings/pylibROM/algo/greedy/pyGreedyCustomSampler.cpp 151 | bindings/pylibROM/algo/greedy/pyGreedyRandomSampler.cpp 152 | bindings/pylibROM/algo/manifold_interp/pyInterpolator.cpp 153 | bindings/pylibROM/algo/manifold_interp/pyMatrixInterpolator.cpp 154 | bindings/pylibROM/algo/manifold_interp/pyVectorInterpolator.cpp 155 | 156 | bindings/pylibROM/hyperreduction/pyDEIM.cpp 157 | bindings/pylibROM/hyperreduction/pyGNAT.cpp 158 | bindings/pylibROM/hyperreduction/pyQDEIM.cpp 159 | bindings/pylibROM/hyperreduction/pyS_OPT.cpp 160 | bindings/pylibROM/hyperreduction/pySTSampling.cpp 161 | bindings/pylibROM/hyperreduction/pyUtilities.cpp 162 | 163 | bindings/pylibROM/utils/mpi_utils.cpp 164 | bindings/pylibROM/utils/pyDatabase.hpp 165 | bindings/pylibROM/utils/pyDatabase.cpp 166 | bindings/pylibROM/utils/pyHDFDatabase.cpp 167 | bindings/pylibROM/utils/pyHDFDatabaseMPIO.cpp 168 | bindings/pylibROM/utils/pyCSVDatabase.cpp 169 | 170 | bindings/pylibROM/python_utils/cpp_utils.hpp 171 | ) 172 | 173 | if (USE_MFEM) 174 | set(PYLIBROM_SOURCES ${PYLIBROM_SOURCES} 175 | bindings/pylibROM/mfem/pyUtilities.cpp 176 | bindings/pylibROM/mfem/pyPointwiseSnapshot.cpp 177 | bindings/pylibROM/mfem/pySampleMesh.cpp) 178 | endif() 179 | 180 | pybind11_add_module(_pylibROM ${PYLIBROM_SOURCES}) 181 | message("building pylibROM...") 182 | 183 | if (USE_MFEM) 184 | target_include_directories( 185 | _pylibROM 186 | PUBLIC 187 | ${MFEM_INCLUDES} 188 | ${HYPRE_INCLUDES} 189 | ${PARMETIS_INCLUDES} 190 | ${MFEM_C_INCLUDE_DIRS}) 191 | 192 | target_link_libraries( 193 | _pylibROM 194 | PUBLIC 195 | ${MFEM} 196 | ${HYPRE} 197 | ${PARMETIS} 198 | ${METIS}) 199 | endif() 200 | 201 | target_link_libraries(_pylibROM PRIVATE ROM) 202 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Lawrence Livermore National Laboratory 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # pylibROM 2 | Python Interface for LLNL libROM 3 | 4 | ## Installation 5 | 6 | 1. Pull repository and all sub-module dependencies: 7 | ``` 8 | git clone --recurse-submodules https://github.com/llnl/pylibROM.git 9 | ``` 10 | 11 | 2. Compile and build pylibROM (from top-level pylibROM repo): 12 | ``` 13 | pip install ./ 14 | ``` 15 | To speed up the build if libROM has been compiled: 16 | ``` 17 | pip install ./ --global-option="--librom_dir=/path/to/pre-installed-libROM" 18 | ``` 19 | If you want to build static ScaLAPACK for libROM, 20 | ``` 21 | pip install ./ --global-option="--install_scalapack" 22 | ``` 23 | 24 | 3. Test python package (from top-level pylibROM repo): 25 | ``` 26 | cd tests 27 | pytest test_pyVector.py 28 | ``` 29 | 30 | ### Using PyMFEM 31 | `pylibROM` is often used together with [`PyMFEM`](https://github.com/mfem/PyMFEM). 32 | Check the repository for detailed instruction for `PyMFEM` installation. 33 | For serial version of `PyMFEM`, the following simple `pip` command works: 34 | ``` 35 | pip install mfem 36 | ``` 37 | For parallel version, a manual installation is required: 38 | ``` 39 | git clone https://github.com/mfem/PyMFEM.git 40 | cd PyMFEM 41 | python3 setup.py install --with-parallel --with-gslib 42 | ``` 43 | On LC quartz, use `--user` flag: 44 | ``` 45 | python3 setup.py install --with-parallel --with-gslib --user 46 | ``` 47 | Make sure [`swig`](https://pypi.org/project/swig) is installed first. Also, the binary file must be located in `PATH` environment variable. 48 | 49 | ### pylibROM-Jupyter Docker Container 50 | 51 | This Docker container provides an environment with Jupyter Notebook for the pylibROM library. Follow the steps below to build the Docker image and run a Jupyter Notebook server. 52 | 53 | #### Build the Docker Image 54 | 55 | Navigate to the directory containing the Dockerfile: 56 | ``` 57 | cd /path/to/folder/pylibROM/docker/jupyter 58 | ``` 59 | 60 | Now, run the following command to build the Docker image: 61 | 62 | ``` 63 | docker build -t pylibrom-jupyter:latest . 64 | ``` 65 | 66 | Once the image is built, you can run a container and start a Jupyter Notebook server. Replace /path/to/host/folder with the absolute path to the local directory you want to mount inside the container for Jupyter notebooks: 67 | 68 | ``` 69 | docker run -p 8888:8888 -v /path/to/host/folder:/notebooks -w /notebooks pylibrom-jupyter:latest 70 | ``` 71 | 72 | 73 | ## License 74 | pylibROM is distributed under the terms of the MIT license. All new contributions must be made under the MIT. See 75 | [LICENSE-MIT](https://github.com/LLNL/pylibROM/blob/main/LICENSE) 76 | 77 | LLNL Release Nubmer: LLNL-CODE- 852921 78 | 79 | 80 | ## Authors 81 | - Michael Barrow (LLNL) 82 | - Siu Wun Cheung (LLNL) 83 | - Youngsoo Choi (LLNL) 84 | - "Kevin" Seung Whan Chung (LLNL) 85 | - Pravija Danda (TAMU) 86 | - Coleman Kendrick (LLNL) 87 | - Hardeep Sullan (LLNL) 88 | - Jian Tao (TAMU) 89 | - Henry Yu (LLNL) 90 | -------------------------------------------------------------------------------- /bindings/.bash_history: -------------------------------------------------------------------------------- 1 | start_new_history 2 | #1684527709 3 | cd ../ 4 | -------------------------------------------------------------------------------- /bindings/pylibROM/__init__.py: -------------------------------------------------------------------------------- 1 | # from . import linalg 2 | # from . import algo 3 | # from . import utils 4 | # from . import hyperreduction 5 | # To add pure python routines to this module, 6 | # either define/import the python routine in this file. 7 | # This will combine both c++ bindings/pure python routines into this module. 8 | 9 | from _pylibROM.algo import * 10 | from _pylibROM.hyperreduction import * 11 | from _pylibROM.linalg import * 12 | 13 | try: 14 | import _pylibROM.mfem 15 | from _pylibROM.mfem import * 16 | except: 17 | pass 18 | 19 | from _pylibROM.utils import * 20 | -------------------------------------------------------------------------------- /bindings/pylibROM/algo/__init__.py: -------------------------------------------------------------------------------- 1 | # To add pure python routines to this module, 2 | # either define/import the python routine in this file. 3 | # This will combine both c++ bindings/pure python routines into this module. 4 | 5 | # For other c++ binding modules, change the module name accordingly. 6 | from _pylibROM.algo import * -------------------------------------------------------------------------------- /bindings/pylibROM/algo/greedy/__init__.py: -------------------------------------------------------------------------------- 1 | # To add pure python routines to this module, 2 | # either define/import the python routine in this file. 3 | # This will combine both c++ bindings/pure python routines into this module. 4 | 5 | # For other c++ binding modules, change the module name accordingly. 6 | from _pylibROM.algo.greedy import * -------------------------------------------------------------------------------- /bindings/pylibROM/algo/greedy/pyGreedyCustomSampler.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "algo/greedy/GreedyCustomSampler.h" 6 | #include "linalg/Vector.h" 7 | 8 | namespace py = pybind11; 9 | using namespace CAROM; 10 | using namespace std; 11 | 12 | void init_GreedyCustomSampler(pybind11::module_ &m) { 13 | py::class_(m, "GreedyCustomSampler") 14 | .def(py::init, bool, double, double, double, int, int, std::string, std::string, bool, int, bool>(), 15 | py::arg("parameter_points"), 16 | py::arg("check_local_rom"), 17 | py::arg("relative_error_tolerance"), 18 | py::arg("alpha"), 19 | py::arg("max_clamp"), 20 | py::arg("subset_size"), 21 | py::arg("convergence_subset_size"), 22 | py::arg("output_log_path") = "", 23 | py::arg("warm_start_file_name") = "", 24 | py::arg("use_centroid") = true, 25 | py::arg("random_seed") = 1, 26 | py::arg("debug_algorithm") = false) 27 | .def(py::init, bool, double, double, double, int, int, std::string, std::string, bool, int, bool>(), 28 | py::arg("parameter_points"), 29 | py::arg("check_local_rom"), 30 | py::arg("relative_error_tolerance"), 31 | py::arg("alpha"), 32 | py::arg("max_clamp"), 33 | py::arg("subset_size"), 34 | py::arg("convergence_subset_size"), 35 | py::arg("output_log_path") = "", 36 | py::arg("warm_start_file_name") = "", 37 | py::arg("use_centroid") = true, 38 | py::arg("random_seed") = 1, 39 | py::arg("debug_algorithm") = false) 40 | .def(py::init(), 41 | py::arg("base_file_name"), 42 | py::arg("output_log_path") = "") 43 | .def("__del__", [](GreedyCustomSampler& self){ self.~GreedyCustomSampler(); }); 44 | } 45 | -------------------------------------------------------------------------------- /bindings/pylibROM/algo/greedy/pyGreedyRandomSampler.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "algo/greedy/GreedyRandomSampler.h" 6 | #include "linalg/Vector.h" 7 | 8 | namespace py = pybind11; 9 | using namespace CAROM; 10 | using namespace std; 11 | 12 | void init_GreedyRandomSampler(py::module &m) { 13 | py::class_(m, "GreedyRandomSampler") 14 | .def(py::init(), 15 | py::arg("param_space_min"), 16 | py::arg("param_space_max"), 17 | py::arg("num_parameter_points"), 18 | py::arg("check_local_rom"), 19 | py::arg("relative_error_tolerance"), 20 | py::arg("alpha"), 21 | py::arg("max_clamp"), 22 | py::arg("subset_size"), 23 | py::arg("convergence_subset_size"), 24 | py::arg("use_latin_hypercube"), 25 | py::arg("output_log_path") = "", 26 | py::arg("warm_start_file_name") = "", 27 | py::arg("use_centroid") = true, 28 | py::arg("random_seed") = 1, 29 | py::arg("debug_algorithm") = false 30 | ) 31 | .def(py::init(), 32 | py::arg("param_space_min"), 33 | py::arg("param_space_max"), 34 | py::arg("num_parameter_points"), 35 | py::arg("check_local_rom"), 36 | py::arg("relative_error_tolerance"), 37 | py::arg("alpha"), 38 | py::arg("max_clamp"), 39 | py::arg("subset_size"), 40 | py::arg("convergence_subset_size"), 41 | py::arg("use_latin_hypercube"), 42 | py::arg("output_log_path") = "", 43 | py::arg("warm_start_file_name") = "", 44 | py::arg("use_centroid") = true, 45 | py::arg("random_seed") = 1, 46 | py::arg("debug_algorithm") = false 47 | ) 48 | .def(py::init(), 49 | py::arg("base_file_name"), 50 | py::arg("output_log_path") = "" 51 | ) 52 | .def("save", &GreedyRandomSampler::save, py::arg("base_file_name")) 53 | .def("__del__", [](GreedyRandomSampler& self){ self.~GreedyRandomSampler(); }); 54 | } 55 | -------------------------------------------------------------------------------- /bindings/pylibROM/algo/greedy/pyGreedySampler.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "algo/greedy/GreedySampler.h" 6 | #include "linalg/Vector.h" 7 | 8 | namespace py = pybind11; 9 | using namespace CAROM; 10 | using namespace std; 11 | 12 | 13 | class PyGreedySampler : public GreedySampler { 14 | public: 15 | using GreedySampler::GreedySampler; 16 | 17 | void save(std::string base_file_name) override { 18 | PYBIND11_OVERRIDE(void,GreedySampler,save,base_file_name ); 19 | } 20 | protected: 21 | void constructParameterPoints() override { 22 | PYBIND11_OVERRIDE_PURE(void, GreedySampler, constructParameterPoints,); 23 | } 24 | void getNextParameterPointAfterConvergenceFailure() override { 25 | PYBIND11_OVERRIDE_PURE(void, GreedySampler, getNextParameterPointAfterConvergenceFailure,); 26 | } 27 | }; 28 | 29 | void init_GreedySampler(pybind11::module_ &m) { 30 | py::class_(m, "GreedyErrorIndicatorPoint") 31 | .def_property_readonly("point", [](GreedyErrorIndicatorPoint &self) { 32 | return self.point.get(); 33 | }) 34 | .def_property_readonly("localROM", [](GreedyErrorIndicatorPoint &self) { 35 | return self.localROM.get(); 36 | }); 37 | 38 | py::class_(m, "GreedySampler") 39 | .def(py::init, bool, double, double, double, int, int, std::string, std::string, bool, int, bool>(), 40 | py::arg("parameter_points"), 41 | py::arg("check_local_rom"), 42 | py::arg("relative_error_tolerance"), 43 | py::arg("alpha"), 44 | py::arg("max_clamp"), 45 | py::arg("subset_size"), 46 | py::arg("convergence_subset_size"), 47 | py::arg("output_log_path") = "", 48 | py::arg("warm_start_file_name") = "", 49 | py::arg("use_centroid") = true, 50 | py::arg("random_seed") = 1, 51 | py::arg("debug_algorithm") = false) 52 | .def(py::init,bool, double, double, double, int, int, std::string, std::string, bool, int, bool>(), 53 | py::arg("parameter_points"), 54 | py::arg("check_local_rom"), 55 | py::arg("relative_error_tolerance"), 56 | py::arg("alpha"), 57 | py::arg("max_clamp"), 58 | py::arg("subset_size"), 59 | py::arg("convergence_subset_size"), 60 | py::arg("output_log_path") = "", 61 | py::arg("warm_start_file_name") = "", 62 | py::arg("use_centroid") = true, 63 | py::arg("random_seed") = 1, 64 | py::arg("debug_algorithm") = false) 65 | .def(py::init(), 66 | py::arg("param_space_min"), py::arg("param_space_max"), py::arg("num_parameter_points"), 67 | py::arg("check_local_rom"), py::arg("relative_error_tolerance"), py::arg("alpha"), 68 | py::arg("max_clamp"), py::arg("subset_size"), py::arg("convergence_subset_size"), 69 | py::arg("output_log_path") = "", py::arg("warm_start_file_name") = "", 70 | py::arg("use_centroid") = true, py::arg("random_seed") = 1, 71 | py::arg("debug_algorithm") = false 72 | ) 73 | .def(py::init(), 74 | py::arg("param_space_min"), py::arg("param_space_max"), py::arg("num_parameter_points"), 75 | py::arg("check_local_rom"), py::arg("relative_error_tolerance"), py::arg("alpha"), 76 | py::arg("max_clamp"), py::arg("subset_size"), py::arg("convergence_subset_size"), 77 | py::arg("output_log_path") = "", py::arg("warm_start_file_name") = "", 78 | py::arg("use_centroid") = true, py::arg("random_seed") = 1, 79 | py::arg("debug_algorithm") = false 80 | ) 81 | .def(py::init(), py::arg("base_file_name"), py::arg("output_log_path") = "") 82 | .def("getNextParameterPoint", [](GreedySampler& self) -> std::unique_ptr { 83 | std::shared_ptr result = self.getNextParameterPoint(); 84 | return std::make_unique(*(result.get())); 85 | }) 86 | .def("getNextPointRequiringRelativeError", [](GreedySampler& self) -> GreedyErrorIndicatorPoint { 87 | // Create a deepcopy of the struct, otherwise it will get freed twice 88 | GreedyErrorIndicatorPoint point = self.getNextPointRequiringRelativeError(); 89 | Vector *t_pt = nullptr; 90 | Vector *t_lROM = nullptr; 91 | 92 | if (point.point) 93 | { 94 | t_pt = new Vector(*(point.point)); 95 | } 96 | 97 | if (point.localROM) 98 | { 99 | t_lROM = new Vector(*(point.localROM)); 100 | } 101 | 102 | return createGreedyErrorIndicatorPoint(t_pt, t_lROM); 103 | }, py::return_value_policy::reference) 104 | .def("getNextPointRequiringErrorIndicator", [](GreedySampler& self) -> GreedyErrorIndicatorPoint { 105 | // Create a deepcopy of the struct, otherwise it will get freed twice 106 | GreedyErrorIndicatorPoint point = self.getNextPointRequiringErrorIndicator(); 107 | 108 | Vector *t_pt = nullptr; 109 | Vector *t_lROM = nullptr; 110 | 111 | if (point.point) 112 | { 113 | t_pt = new Vector(*(point.point)); 114 | } 115 | 116 | if (point.localROM) 117 | { 118 | t_lROM = new Vector(*(point.localROM)); 119 | } 120 | 121 | return createGreedyErrorIndicatorPoint(t_pt, t_lROM); 122 | }, py::return_value_policy::reference) 123 | .def("setPointRelativeError", (void (GreedySampler::*) (double))&GreedySampler::setPointRelativeError) 124 | .def("setPointErrorIndicator", (void (GreedySampler::*) (double,int)) &GreedySampler::setPointErrorIndicator) 125 | .def("getNearestNonSampledPoint", (int (GreedySampler::*) (CAROM::Vector)) &GreedySampler::getNearestNonSampledPoint) 126 | .def("getNearestROM", [](GreedySampler& self, Vector point) -> std::unique_ptr { 127 | std::shared_ptr result = self.getNearestROM(point); 128 | if (!result) 129 | { 130 | return nullptr; 131 | } 132 | return std::make_unique(*(result.get())); 133 | }) 134 | .def("getParameterPointDomain", &GreedySampler::getParameterPointDomain) 135 | .def("getSampledParameterPoints", &GreedySampler::getSampledParameterPoints) 136 | .def("save", &GreedySampler::save) 137 | .def("__del__", [](GreedySampler& self){ self.~GreedySampler(); }) 138 | .def("isComplete", &GreedySampler::isComplete); 139 | 140 | m.def("createGreedyErrorIndicatorPoint", [](Vector* point, Vector* localROM) { 141 | return createGreedyErrorIndicatorPoint(point, localROM); 142 | }); 143 | m.def("createGreedyErrorIndicatorPoint", [](Vector* point, std::shared_ptr& localROM) { 144 | return createGreedyErrorIndicatorPoint(point, localROM); 145 | }); 146 | m.def("getNearestPoint", [](std::vector& paramPoints,Vector point) { 147 | return getNearestPoint(paramPoints, point); 148 | }); 149 | m.def("getNearestPoint", [](std::vector& paramPoints, double point) { 150 | return getNearestPoint(paramPoints, point); 151 | }); 152 | m.def("getNearestPointIndex", [](std::vector paramPoints, Vector point) { 153 | return getNearestPointIndex(paramPoints, point); 154 | }); 155 | m.def("getNearestPointIndex", [](std::vector paramPoints, double point) { 156 | return getNearestPointIndex(paramPoints, point); 157 | }); 158 | } 159 | -------------------------------------------------------------------------------- /bindings/pylibROM/algo/manifold_interp/__init__.py: -------------------------------------------------------------------------------- 1 | from _pylibROM.algo.manifold_interp import * -------------------------------------------------------------------------------- /bindings/pylibROM/algo/manifold_interp/pyInterpolator.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "linalg/Matrix.h" 6 | #include "linalg/Vector.h" 7 | #include "algo/manifold_interp/Interpolator.h" 8 | 9 | namespace py = pybind11; 10 | using namespace CAROM; 11 | 12 | void 13 | init_Interpolator(pybind11::module_ &m) 14 | { 15 | m.def("obtainRBFToTrainingPoints", &obtainRBFToTrainingPoints); 16 | m.def("rbfWeightedSum", &rbfWeightedSum); 17 | m.def("obtainRBF", &obtainRBF); 18 | m.def("convertClosestRBFToEpsilon", &convertClosestRBFToEpsilon); 19 | m.def("obtainRotationMatrices", &obtainRotationMatrices); 20 | } 21 | -------------------------------------------------------------------------------- /bindings/pylibROM/algo/manifold_interp/pyMatrixInterpolator.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "linalg/Matrix.h" 6 | #include "linalg/Vector.h" 7 | #include "algo/manifold_interp/MatrixInterpolator.h" 8 | 9 | namespace py = pybind11; 10 | using namespace CAROM; 11 | 12 | void 13 | init_MatrixInterpolator(pybind11::module_ &m) 14 | { 15 | py::class_(m, "MatrixInterpolator") 16 | .def(py::init, std::vector, std::vector, int, std::string, std::string, std::string, double>(), 17 | py::arg("parameter_points"), 18 | py::arg("rotation_matrices"), 19 | py::arg("reduced_matrices"), 20 | py::arg("ref_point"), 21 | py::arg("matrix_type"), 22 | py::arg("rbf") = "G", 23 | py::arg("interp_method") = "LS", 24 | py::arg("closest_rbf_val") = 0.9) 25 | .def("interpolate", &MatrixInterpolator::interpolate, py::arg("point"), py::arg("orthogonalize") = false) 26 | .def("__del__", [](MatrixInterpolator& self) { self.~MatrixInterpolator(); }); 27 | } 28 | -------------------------------------------------------------------------------- /bindings/pylibROM/algo/manifold_interp/pyVectorInterpolator.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "linalg/Matrix.h" 6 | #include "linalg/Vector.h" 7 | #include "algo/manifold_interp/VectorInterpolator.h" 8 | 9 | namespace py = pybind11; 10 | using namespace CAROM; 11 | 12 | void 13 | init_VectorInterpolator(pybind11::module_ &m) 14 | { 15 | py::class_(m, "VectorInterpolator") 16 | .def(py::init, std::vector, std::vector, int, std::string, std::string, double>(), 17 | py::arg("parameter_points"), 18 | py::arg("rotation_matrices"), 19 | py::arg("reduced_vectors"), 20 | py::arg("ref_point"), 21 | py::arg("rbf") = "G", 22 | py::arg("interp_method") = "LS", 23 | py::arg("closest_rbf_val") = 0.9) 24 | .def("interpolate", &VectorInterpolator::interpolate) 25 | .def("__del__", [](VectorInterpolator& self) { self.~VectorInterpolator(); }); 26 | 27 | m.def("obtainInterpolatedVector", &obtainInterpolatedVector); 28 | m.def("solveLinearSystem", &solveLinearSystem); 29 | } 30 | -------------------------------------------------------------------------------- /bindings/pylibROM/algo/pyAdaptiveDMD.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "algo/AdaptiveDMD.h" 4 | #include "linalg/Vector.h" 5 | #include "linalg/Matrix.h" 6 | 7 | namespace py = pybind11; 8 | using namespace CAROM; 9 | 10 | void init_AdaptiveDMD(pybind11::module_ &m){ 11 | 12 | py::class_(m, "AdaptiveDMD") 13 | .def(py::init(), 14 | py::arg("dim"), 15 | py::arg("desired_dt") = -1.0, 16 | py::arg("rbf") = "G", 17 | py::arg("interp_method") = "LS", 18 | py::arg("closest_rbf_val") = 0.9, 19 | py::arg("alt_output_basis") = false, 20 | py::arg("state_offset") = nullptr) 21 | .def("train", (void (AdaptiveDMD::*)(double, const Matrix*, double)) &AdaptiveDMD::train, 22 | py::arg("energy_fraction").noconvert(), 23 | py::arg("W0") = nullptr, 24 | py::arg("linearity_tol") = 0.0) 25 | .def("train", (void (AdaptiveDMD::*)(int, const Matrix*, double)) &AdaptiveDMD::train, 26 | py::arg("k").noconvert(), 27 | py::arg("W0") = nullptr, 28 | py::arg("linearity_tol") = 0.0) 29 | .def("getTrueDt", &AdaptiveDMD::getTrueDt) 30 | .def("getInterpolatedSnapshots", &AdaptiveDMD::getInterpolatedSnapshots); 31 | } 32 | 33 | -------------------------------------------------------------------------------- /bindings/pylibROM/algo/pyNonuniformDMD.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by barrow9 on 6/4/23. 3 | // 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "librom.h" 9 | #include "python_utils/cpp_utils.hpp" 10 | 11 | namespace py = pybind11; 12 | using namespace CAROM; 13 | 14 | void init_NonuniformDMD(pybind11::module_ &m) { 15 | 16 | py::class_(m, "NonuniformDMD") 17 | 18 | //constructor, default. 19 | .def(py::init()) //constructor a 20 | 21 | .def(py::init([](int dim, 22 | bool alt_output_basis, 23 | Vector* state_offset, 24 | Vector* derivative_offset) { 25 | return new NonuniformDMD(dim, alt_output_basis, state_offset, derivative_offset); 26 | }), 27 | py::arg("dim"), 28 | py::arg("alt_output_basis") = false, 29 | py::arg("state_offset") = nullptr, 30 | py::arg("derivative_offset") = nullptr) 31 | 32 | //TODO: needed explicitly? 33 | .def("__del__", [](NonuniformDMD& self) { self.~NonuniformDMD(); }) // Destructor 34 | 35 | .def("setOffset", &NonuniformDMD::setOffset, py::arg("offset_vector"), py::arg("order")) 36 | 37 | .def("load", &NonuniformDMD::load, py::arg("base_file_name")) 38 | .def("save", &NonuniformDMD::save, py::arg("base_file_name")); 39 | 40 | } 41 | -------------------------------------------------------------------------------- /bindings/pylibROM/algo/pyParametricDMD.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by barrow9 on 6/4/23. 3 | // 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "algo/DMD.h" 9 | #include "algo/ParametricDMD.h" 10 | #include "linalg/Vector.h" 11 | #include "python_utils/cpp_utils.hpp" 12 | 13 | namespace py = pybind11; 14 | using namespace CAROM; 15 | using namespace std; 16 | 17 | template 18 | T* getParametricDMD_Type( 19 | std::vector& parameter_points, 20 | std::vector& dmds, 21 | Vector* desired_point, 22 | std::string rbf, 23 | std::string interp_method, 24 | double closest_rbf_val, 25 | bool reorthogonalize_W) 26 | { 27 | T *parametric_dmd = NULL; 28 | getParametricDMD(parametric_dmd, parameter_points, dmds, desired_point, 29 | rbf, interp_method, closest_rbf_val, reorthogonalize_W); 30 | return parametric_dmd; 31 | } 32 | 33 | template 34 | T* getParametricDMD_Type( 35 | std::vector& parameter_points, 36 | std::vector& dmd_paths, 37 | Vector* desired_point, 38 | std::string rbf = "G", 39 | std::string interp_method = "LS", 40 | double closest_rbf_val = 0.9, 41 | bool reorthogonalize_W = false) 42 | { 43 | T *parametric_dmd = NULL; 44 | getParametricDMD(parametric_dmd, parameter_points, dmd_paths, desired_point, 45 | rbf, interp_method, closest_rbf_val, reorthogonalize_W); 46 | return parametric_dmd; 47 | } 48 | 49 | void init_ParametricDMD(pybind11::module_ &m) { 50 | 51 | // original getParametricDMD pass a template pointer reference T* ¶metric_dmd. 52 | // While it is impossible to bind a template function as itself, 53 | // this first argument T* ¶metric_dmd is mainly for determining the type T. 54 | // Here we introduce a dummy argument in place of parametric_dmd. 55 | // This will let python decide which function to use, based on the first argument type. 56 | // We will need variants of this as we bind more DMD classes, 57 | // where dmd_type is the corresponding type. 58 | m.def("getParametricDMD", []( 59 | py::object &dmd_type, 60 | std::vector& parameter_points, 61 | std::vector& dmds, 62 | Vector* desired_point, 63 | std::string rbf = "G", 64 | std::string interp_method = "LS", 65 | double closest_rbf_val = 0.9, 66 | bool reorthogonalize_W = false) 67 | { 68 | std::string name = dmd_type.attr("__name__").cast(); 69 | if (name == "DMD") 70 | return getParametricDMD_Type(parameter_points, dmds, desired_point, 71 | rbf, interp_method, closest_rbf_val, reorthogonalize_W); 72 | else 73 | { 74 | std::string msg = name + " is not a proper libROM DMD class!\n"; 75 | throw std::runtime_error(msg.c_str()); 76 | } 77 | }, 78 | py::arg("dmd_type"), 79 | py::arg("parameter_points"), 80 | py::arg("dmds"), 81 | py::arg("desired_point"), 82 | py::arg("rbf") = "G", 83 | py::arg("interp_method") = "LS", 84 | py::arg("closest_rbf_val") = 0.9, 85 | py::arg("reorthogonalize_W") = false); 86 | 87 | // original getParametricDMD pass a template pointer reference T* ¶metric_dmd. 88 | // While it is impossible to bind a template function as itself, 89 | // this first argument T* ¶metric_dmd is mainly for determining the type T. 90 | // Here we introduce a dummy argument in place of parametric_dmd. 91 | // This will let python decide which function to use, based on the first argument type. 92 | // We will need variants of this as we bind more DMD classes, 93 | // where dmd_type is the corresponding type. 94 | m.def("getParametricDMD", []( 95 | py::object &dmd_type, 96 | std::vector& parameter_points, 97 | std::vector& dmd_paths, 98 | Vector* desired_point, 99 | std::string rbf = "G", 100 | std::string interp_method = "LS", 101 | double closest_rbf_val = 0.9, 102 | bool reorthogonalize_W = false) 103 | { 104 | std::string name = dmd_type.attr("__name__").cast(); 105 | if (name == "DMD") 106 | return getParametricDMD_Type(parameter_points, dmd_paths, desired_point, 107 | rbf, interp_method, closest_rbf_val, reorthogonalize_W); 108 | else 109 | { 110 | std::string msg = name + " is not a proper libROM DMD class!\n"; 111 | throw std::runtime_error(msg.c_str()); 112 | } 113 | }, 114 | py::arg("dmd_type"), 115 | py::arg("parameter_points"), 116 | py::arg("dmd_paths"), 117 | py::arg("desired_point"), 118 | py::arg("rbf") = "G", 119 | py::arg("interp_method") = "LS", 120 | py::arg("closest_rbf_val") = 0.9, 121 | py::arg("reorthogonalize_W") = false); 122 | 123 | } 124 | -------------------------------------------------------------------------------- /bindings/pylibROM/hyperreduction/__init__.py: -------------------------------------------------------------------------------- 1 | from _pylibROM.hyperreduction import * -------------------------------------------------------------------------------- /bindings/pylibROM/hyperreduction/pyDEIM.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "hyperreduction/DEIM.h" 6 | #include 7 | #include "linalg/Matrix.h" 8 | 9 | namespace py = pybind11; 10 | using namespace CAROM; 11 | 12 | 13 | void init_DEIM(pybind11::module_ &m) { 14 | m.def("DEIM", [](const Matrix* f_basis,int num_f_basis_vectors_used, 15 | Matrix& f_basis_sampled_inv,int myid,int num_procs) { 16 | int num_basis_vectors = std::min(num_f_basis_vectors_used, f_basis->numColumns()); 17 | std::vector f_sampled_row(num_basis_vectors); 18 | std::vector f_sampled_rows_per_proc(num_procs); 19 | DEIM(f_basis, num_f_basis_vectors_used,f_sampled_row, f_sampled_rows_per_proc,f_basis_sampled_inv, myid, num_procs); 20 | return std::make_tuple(std::move(f_sampled_row), std::move(f_sampled_rows_per_proc)); 21 | }); 22 | } -------------------------------------------------------------------------------- /bindings/pylibROM/hyperreduction/pyGNAT.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "hyperreduction/GNAT.h" 6 | #include "linalg/Matrix.h" 7 | 8 | namespace py = pybind11; 9 | using namespace CAROM; 10 | 11 | void init_GNAT(pybind11::module_ &m) { 12 | m.def("GNAT", [](const Matrix* f_basis, 13 | const int num_f_basis_vectors_used, 14 | Matrix& f_basis_sampled_inv, 15 | const int myid, 16 | const int num_procs, 17 | const int num_samples_req, 18 | std::vector& init_samples){ 19 | 20 | const int num_basis_vectors = std::min(num_f_basis_vectors_used, f_basis->numColumns()); 21 | const int num_samples = num_samples_req > 0 ? num_samples_req : num_basis_vectors; 22 | std::vector f_sampled_row(num_samples); 23 | std::vector f_sampled_rows_per_proc(num_procs); 24 | GNAT(f_basis, num_f_basis_vectors_used, f_sampled_row, f_sampled_rows_per_proc, 25 | f_basis_sampled_inv, myid, num_procs, num_samples_req,&init_samples); 26 | return std::make_tuple(std::move(f_sampled_row), std::move(f_sampled_rows_per_proc)); 27 | },py::arg("f_basis"), 28 | py::arg("num_f_basis_vectors_used"), 29 | py::arg("f_basis_sampled_inv"), 30 | py::arg("myid"), 31 | py::arg("num_procs"), 32 | py::arg("num_samples_req") = -1, 33 | py::arg("init_samples") = std::vector(0)); 34 | } -------------------------------------------------------------------------------- /bindings/pylibROM/hyperreduction/pyQDEIM.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "hyperreduction/QDEIM.h" 6 | #include 7 | #include "linalg/Matrix.h" 8 | 9 | namespace py = pybind11; 10 | using namespace CAROM; 11 | 12 | void init_QDEIM(pybind11::module_ &m) { 13 | m.def("QDEIM", [](const Matrix* f_basis,int num_f_basis_vectors_used, 14 | Matrix& f_basis_sampled_inv,const int myid,const int num_procs,const int num_samples_req) { 15 | std::vector f_sampled_row(num_samples_req); 16 | std::vector f_sampled_rows_per_proc(num_procs); 17 | QDEIM(f_basis, num_f_basis_vectors_used,f_sampled_row, f_sampled_rows_per_proc,f_basis_sampled_inv, myid, num_procs,num_samples_req); 18 | return std::make_tuple(std::move(f_sampled_row), std::move(f_sampled_rows_per_proc)); 19 | }); 20 | } 21 | 22 | -------------------------------------------------------------------------------- /bindings/pylibROM/hyperreduction/pySTSampling.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "librom.h" 6 | #include "python_utils/cpp_utils.hpp" 7 | 8 | namespace py = pybind11; 9 | using namespace CAROM; 10 | 11 | 12 | void init_STSampling(pybind11::module_ &m) { 13 | m.def("SpaceTimeSampling", [](const Matrix* s_basis, 14 | const Matrix* t_basis, 15 | const int num_f_basis_vectors_used, 16 | py::array_t& f_sampled_row, 17 | py::array_t& f_sampled_rows_per_proc, 18 | Matrix& s_basis_sampled, 19 | const int myid, 20 | const int num_procs, 21 | const int num_t_samples_req = -1, 22 | const int num_s_samples_req = -1, 23 | const bool excludeFinalTime = false) { 24 | std::vector t_samples(num_t_samples_req); 25 | SpaceTimeSampling(s_basis, t_basis,num_f_basis_vectors_used,t_samples,getVectorPointer(f_sampled_row), getVectorPointer(f_sampled_rows_per_proc), s_basis_sampled, myid, num_procs, num_t_samples_req,num_s_samples_req,excludeFinalTime); 26 | return std::move(t_samples); 27 | }, py::arg("s_basis"), py::arg("t_basis"), py::arg("num_f_basis_vectors_used"), 28 | py::arg("f_sampled_row"), py::arg("f_sampled_rows_per_proc"), 29 | py::arg("s_basis_sampled"), py::arg("myid"), py::arg("num_procs"), 30 | py::arg("num_t_samples_req") = -1, py::arg("num_s_samples_req") = -1, 31 | py::arg("excludeFinalTime") = false); 32 | 33 | m.def("GetSampledSpaceTimeBasis", [](std::vector const& t_samples, 34 | const Matrix* t_basis, 35 | Matrix const& s_basis_sampled, 36 | Matrix& f_basis_sampled_inv) { 37 | GetSampledSpaceTimeBasis(t_samples,t_basis,s_basis_sampled,f_basis_sampled_inv); 38 | }); 39 | } 40 | -------------------------------------------------------------------------------- /bindings/pylibROM/hyperreduction/pyS_OPT.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "hyperreduction/S_OPT.h" 7 | #include "linalg/Matrix.h" 8 | 9 | namespace py = pybind11; 10 | using namespace CAROM; 11 | 12 | void init_S_OPT(pybind11::module_ &m) { 13 | m.def("S_OPT", []( 14 | const Matrix* f_basis, 15 | int num_f_basis_vectors_used, 16 | Matrix& f_basis_sampled_inv, 17 | const int myid, 18 | const int num_procs, 19 | const int num_samples_req, 20 | std::vector &init_samples, 21 | bool qr_factorize) { 22 | 23 | // S_OPT checks if f_sample_row and f_sample_rows_per_proc have the right sizes. 24 | // Initialize them with the right size. 25 | const int num_basis_vectors = 26 | std::min(num_f_basis_vectors_used, f_basis->numColumns()); 27 | const int num_samples = num_samples_req > 0 ? num_samples_req : 28 | num_basis_vectors; 29 | std::vector f_sampled_row(num_samples); 30 | std::vector f_sampled_rows_per_proc(num_procs); 31 | 32 | S_OPT(f_basis, num_f_basis_vectors_used, f_sampled_row, 33 | f_sampled_rows_per_proc, f_basis_sampled_inv, myid, 34 | num_procs, num_samples_req, &init_samples, qr_factorize); 35 | 36 | return std::make_tuple(std::move(f_sampled_row), 37 | std::move(f_sampled_rows_per_proc)); 38 | }, 39 | py::arg("f_basis"), 40 | py::arg("num_f_basis_vectors_used"), 41 | py::arg("f_basis_sampled_inv"), 42 | py::arg("myid"), 43 | py::arg("num_procs"), 44 | py::arg("num_samples_req") = -1, 45 | py::arg("init_samples") = std::vector(0), 46 | py::arg("qr_factorize") = false); 47 | } 48 | -------------------------------------------------------------------------------- /bindings/pylibROM/hyperreduction/pyUtilities.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "hyperreduction/Utilities.h" 6 | #include "mpi.h" 7 | 8 | 9 | namespace py = pybind11; 10 | using namespace CAROM; 11 | 12 | void init_Utilities(pybind11::module_ &m) { 13 | py::class_(m, "RowInfo") 14 | .def(py::init<>()) 15 | .def_readwrite("row_val", &RowInfo::row_val) 16 | .def_readwrite("row", &RowInfo::row) 17 | .def_readwrite("proc", &RowInfo::proc); 18 | } 19 | -------------------------------------------------------------------------------- /bindings/pylibROM/linalg/__init__.py: -------------------------------------------------------------------------------- 1 | # To add pure python routines to this module, 2 | # either define/import the python routine in this file. 3 | # This will combine both c++ bindings/pure python routines into this module. 4 | 5 | # For other c++ binding modules, change the module name accordingly. 6 | from _pylibROM.linalg import * 7 | 8 | -------------------------------------------------------------------------------- /bindings/pylibROM/linalg/pyBasisGenerator.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "linalg/BasisGenerator.h" 6 | #include "python_utils/cpp_utils.hpp" 7 | 8 | namespace py = pybind11; 9 | using namespace CAROM; 10 | 11 | void init_BasisGenerator(pybind11::module_ &m) { 12 | 13 | py::class_(m, "BasisGenerator") 14 | // .def(py::init()) 15 | .def(py::init(), 16 | py::arg("options"), 17 | py::arg("incremental"), 18 | py::arg("basis_file_name") = "", 19 | py::arg("file_format") = Database::formats::HDF5 20 | ) 21 | .def("isNextSample", (bool (BasisGenerator::*)(double)) &BasisGenerator::isNextSample) 22 | .def("updateRightSV", (bool (BasisGenerator::*)()) &BasisGenerator::updateRightSV) 23 | .def("takeSample", [](BasisGenerator& self, py::array_t &u_in, bool add_without_increase = false) { 24 | return self.takeSample(getVectorPointer(u_in), add_without_increase); 25 | }, py::arg("u_in"), py::arg("add_without_increase") = false) 26 | .def("endSamples", &BasisGenerator::endSamples, py::arg("kind") = "basis") 27 | .def("writeSnapshot", (void (BasisGenerator::*)()) &BasisGenerator::writeSnapshot) 28 | .def("loadSamples", (void (BasisGenerator::*)(const std::string&, const std::string&, int, Database::formats)) &BasisGenerator::loadSamples, 29 | py::arg("base_file_name"), 30 | py::arg("kind") = "basis", 31 | py::arg("cut_off") = static_cast(1e9), 32 | py::arg("db_format") = Database::formats::HDF5 33 | ) 34 | .def("computeNextSampleTime", [](BasisGenerator& self, py::array_t &u_in, py::array_t &rhs_in, double time) { 35 | return self.computeNextSampleTime(getVectorPointer(u_in), getVectorPointer(rhs_in), time); 36 | }, py::arg("u_in"), py::arg("rhs_in"), py::arg("time")) 37 | 38 | .def("getSpatialBasis", (const Matrix* (BasisGenerator::*)()) &BasisGenerator::getSpatialBasis,py::return_value_policy::reference) 39 | .def("getTemporalBasis", (const Matrix* (BasisGenerator::*)()) &BasisGenerator::getTemporalBasis,py::return_value_policy::reference) 40 | .def("getSingularValues", (const Vector* (BasisGenerator::*)()) &BasisGenerator::getSingularValues,py::return_value_policy::reference) 41 | .def("getSnapshotMatrix", (const Matrix* (BasisGenerator::*)()) &BasisGenerator::getSnapshotMatrix,py::return_value_policy::reference) 42 | .def("getNumSamples",(int (BasisGenerator::*)() const) &BasisGenerator::getNumSamples) 43 | .def("__del__", [](BasisGenerator& self) { self.~BasisGenerator(); }); // Destructor 44 | 45 | } 46 | -------------------------------------------------------------------------------- /bindings/pylibROM/linalg/pyBasisReader.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "linalg/Matrix.h" 6 | #include "linalg/Vector.h" 7 | #include "linalg/BasisReader.h" 8 | 9 | 10 | namespace py = pybind11; 11 | using namespace CAROM; 12 | 13 | void init_BasisReader(pybind11::module_ &m) { 14 | py::class_(m, "BasisReader") 15 | .def(py::init(), 16 | py::arg("base_file_name"), 17 | py::arg("file_format") = Database::formats::HDF5, 18 | py::arg("dim") = -1 19 | ) 20 | .def("getSpatialBasis",(Matrix* (BasisReader::*)()) &BasisReader::getSpatialBasis) 21 | .def("getSpatialBasis",(Matrix* (BasisReader::*)(int)) &BasisReader::getSpatialBasis, 22 | py::arg("n")) 23 | .def("getSpatialBasis",(Matrix* (BasisReader::*)(int,int)) &BasisReader::getSpatialBasis, 24 | py::arg("start_col"), 25 | py::arg("end_col")) 26 | .def("getSpatialBasis",(Matrix* (BasisReader::*)(double)) &BasisReader::getSpatialBasis, 27 | py::arg("ef").noconvert()) 28 | .def("getTemporalBasis",(Matrix* (BasisReader::*)()) &BasisReader::getTemporalBasis) 29 | .def("getTemporalBasis",(Matrix* (BasisReader::*)(int)) &BasisReader::getTemporalBasis, 30 | py::arg("n")) 31 | .def("getTemporalBasis",(Matrix* (BasisReader::*)(int,int)) &BasisReader::getTemporalBasis, 32 | py::arg("start_col"), 33 | py::arg("end_col")) 34 | .def("getTemporalBasis",(Matrix* (BasisReader::*)(double)) &BasisReader::getTemporalBasis, 35 | py::arg("ef").noconvert()) 36 | .def("getSingularValues",(Vector* (BasisReader::*)()) &BasisReader::getSingularValues) 37 | .def("getSingularValues",(Vector* (BasisReader::*)(double)) &BasisReader::getSingularValues, 38 | py::arg("ef")) 39 | .def("getDim", (int (BasisReader::*)(const std::string)) &BasisReader::getDim, 40 | py::arg("kind")) 41 | .def("getNumSamples", (int (BasisReader::*)(const std::string)) &BasisReader::getNumSamples, 42 | py::arg("kind")) 43 | .def("getSnapshotMatrix",(Matrix* (BasisReader::*)()) &BasisReader::getSnapshotMatrix) 44 | .def("getSnapshotMatrix",(Matrix* (BasisReader::*)(int)) &BasisReader::getSnapshotMatrix, 45 | py::arg("n")) 46 | .def("getSnapshotMatrix",(Matrix* (BasisReader::*)(int,int)) &BasisReader::getSnapshotMatrix, 47 | py::arg("start_col"), 48 | py::arg("end_col")) 49 | .def("__del__", [](BasisReader& self) { self.~BasisReader(); }); // Destructor 50 | } 51 | -------------------------------------------------------------------------------- /bindings/pylibROM/linalg/pyBasisWriter.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "linalg/BasisWriter.h" 6 | #include "linalg/BasisGenerator.h" 7 | 8 | namespace py = pybind11; 9 | using namespace CAROM; 10 | 11 | void init_BasisWriter(pybind11::module_ &m) { 12 | py::class_(m, "BasisWriter") 13 | .def(py::init(), py::arg("basis_generator"), py::arg("base_file_name"), py::arg("db_format") = static_cast(Database::formats::HDF5)) 14 | .def("writeBasis", &BasisWriter::writeBasis, py::arg("kind") = "basis") 15 | .def("__del__", [](BasisWriter& self) { self.~BasisWriter(); }); 16 | } 17 | -------------------------------------------------------------------------------- /bindings/pylibROM/linalg/pyNNLS.cpp: -------------------------------------------------------------------------------- 1 | /***************************************************** 2 | This file creates the python binder for the NNLSSolver 3 | class as defined in libROM/lib/linalg/NNLS. 4 | 5 | created by Henry Yu 06.21.23 6 | *****************************************************/ 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "linalg/NNLS.h" 12 | #include "linalg/Matrix.h" 13 | #include "linalg/Vector.h" 14 | 15 | namespace py = pybind11; 16 | using namespace CAROM; 17 | using namespace pybind11::literals; 18 | 19 | 20 | void init_NNLSSolver(pybind11::module_ &m) { 21 | py::class_(m, "NNLSSolver") 22 | .def(py::init(), 23 | py::arg("const_tol") = 1.0e-14, 24 | py::arg("min_nnz") = 0, 25 | py::arg("max_nnz") = 0, 26 | py::arg("verbosity") = 0, 27 | py::arg("res_change_termination_tol") = 1.0e-4, 28 | py::arg("zero_tol") = 1.0e-14, 29 | py::arg("n_outer") = 100000, 30 | py::arg("n_inner") = 100000) 31 | .def("set_verbosity", &NNLSSolver::set_verbosity, 32 | py::arg("verbosity_in")) 33 | .def("set_qrresidual_mode", &NNLSSolver::set_qrresidual_mode, 34 | py::arg("qr_residual_mode")) 35 | .def("solve_parallel_with_scalapack", &NNLSSolver::solve_parallel_with_scalapack, 36 | py::arg("matTrans"), py::arg("rhs_lb"), py::arg("rhs_ub"), py::arg("soln")) 37 | .def("normalize_constraints", &NNLSSolver::normalize_constraints, 38 | py::arg("matTrans"), py::arg("rhs_lb"), py::arg("rhs_ub")) 39 | .def("getNumProcs", &NNLSSolver::getNumProcs); 40 | 41 | py::enum_(m, "QRresidualMode") 42 | .value("off", NNLSSolver::QRresidualMode::off) 43 | .value("on", NNLSSolver::QRresidualMode::on); 44 | 45 | } 46 | -------------------------------------------------------------------------------- /bindings/pylibROM/linalg/pyOptions.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "linalg/Options.h" 6 | 7 | namespace py = pybind11; 8 | using namespace CAROM; 9 | 10 | void init_Options(pybind11::module_ &m) { 11 | 12 | py::class_(m, "Options") 13 | .def(py::init(), py::arg("dim_"), py::arg("max_num_samples_"),py::arg("update_right_SV_") = false, py::arg("write_snapshots_") = false) 14 | .def_readwrite("dim", &Options::dim) 15 | .def_readwrite("max_num_samples", &Options::max_num_samples) 16 | .def_readwrite("update_right_SV", &Options::update_right_SV) 17 | .def_readwrite("write_snapshots", &Options::write_snapshots) 18 | .def_readwrite("max_basis_dimension", &Options::max_basis_dimension) 19 | .def_readwrite("singular_value_tol", &Options::singular_value_tol) 20 | .def_readwrite("debug_algorithm", &Options::debug_algorithm) 21 | .def_readwrite("randomized", &Options::randomized) 22 | .def_readwrite("randomized_subspace_dim", &Options::randomized_subspace_dim) 23 | .def_readwrite("random_seed", &Options::random_seed) 24 | .def_readwrite("linearity_tol", &Options::linearity_tol) 25 | .def_readwrite("initial_dt", &Options::initial_dt) 26 | .def_readwrite("sampling_tol", &Options::sampling_tol) 27 | .def_readwrite("max_time_between_samples", &Options::max_time_between_samples) 28 | .def_readwrite("fast_update", &Options::fast_update) 29 | .def_readwrite("skip_linearly_dependent", &Options::skip_linearly_dependent) 30 | .def_readwrite("save_state", &Options::save_state) 31 | .def_readwrite("restore_state", &Options::restore_state) 32 | .def_readwrite("min_sampling_time_step_scale", &Options::min_sampling_time_step_scale) 33 | .def_readwrite("sampling_time_step_scale", &Options::sampling_time_step_scale) 34 | .def_readwrite("max_sampling_time_step_scale", &Options::max_sampling_time_step_scale) 35 | .def_readwrite("static_svd_preserve_snapshot", &Options::static_svd_preserve_snapshot) 36 | .def("setMaxBasisDimension", &Options::setMaxBasisDimension, py::arg("max_basis_dimension_")) 37 | .def("setSingularValueTol", &Options::setSingularValueTol, py::arg("singular_value_tol_")) 38 | .def("setDebugMode", &Options::setDebugMode, py::arg("debug_algorithm_")) 39 | .def("setRandomizedSVD", &Options::setRandomizedSVD, py::arg("randomized_"), py::arg("randomized_subspace_dim_") = -1, py::arg("random_seed_") = 1) 40 | .def("setIncrementalSVD", &Options::setIncrementalSVD, 41 | py::arg("linearity_tol_"), 42 | py::arg("initial_dt_"), 43 | py::arg("sampling_tol_"), 44 | py::arg("max_time_between_samples_"), 45 | py::arg("fast_update_") = false, 46 | py::arg("fast_update_brand_") = false, 47 | py::arg("skip_linearly_dependent_") = false 48 | ) 49 | .def("setStateIO", &Options::setStateIO,py::arg("save_state_"),py::arg("restore_state_")) 50 | .def("setSamplingTimeStepScale", &Options::setSamplingTimeStepScale,py::arg("min_sampling_time_step_scale_"),py::arg("sampling_time_step_scale_"),py::arg("max_sampling_time_step_scale_")); 51 | } -------------------------------------------------------------------------------- /bindings/pylibROM/linalg/pyVector.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by sullan2 on 4/20/23. 3 | // 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "linalg/Vector.h" 9 | 10 | namespace py = pybind11; 11 | using namespace CAROM; 12 | 13 | py::buffer_info 14 | bufferInfo(Vector &self) 15 | { 16 | return py::buffer_info( 17 | self.getData(), /* Pointer to buffer */ 18 | sizeof(double), /* Size of one scalar */ 19 | py::format_descriptor::format(), /* Python struct-style format descriptor */ 20 | 1, /* Number of dimensions */ 21 | { self.dim() }, /* Buffer dimensions */ 22 | { sizeof(double) } /* Strides (in bytes) for each index */ 23 | ); 24 | } 25 | 26 | void init_vector(pybind11::module_ &m) { 27 | 28 | py::class_(m, "Vector", py::buffer_protocol()) 29 | .def_buffer([](Vector &self) -> py::buffer_info { 30 | return bufferInfo(self); 31 | }) 32 | 33 | // Constructor 34 | .def(py::init<>()) 35 | .def(py::init()) 36 | 37 | // Constructor 38 | .def(py::init([](py::array_t &vec, bool distributed, bool copy_data = true) { 39 | py::buffer_info buf_info = vec.request(); 40 | int dim = buf_info.shape[0]; 41 | double* data = static_cast(buf_info.ptr); 42 | return new Vector(data, dim, distributed, copy_data); 43 | }), py::arg("vec"), py::arg("distributed"), py::arg("copy_data") = true) // default value needs to be defined here. 44 | 45 | // Bind the copy constructor 46 | .def(py::init()) 47 | 48 | // Bind the assignment operator 49 | .def("__assign__", [](Vector& self, const Vector& rhs) { self = rhs; return self; }) 50 | 51 | // Bind the addition operator 52 | .def(py::self += py::self) 53 | 54 | // Bind the subtraction operator 55 | .def(py::self -= py::self) 56 | 57 | //.def(py::self *= py::self) 58 | .def("fill", [](Vector& self, const double& value) { self = value; }) 59 | 60 | //Bind the equal operator (set every element to a scalar) 61 | .def("__set_scalar__", [](Vector& self, const double& a) { self = a; }) 62 | 63 | //Bind the scaling operator (scale every element by a scalar) 64 | .def("__scale__", [](Vector& self, const double& a) { self *= a; }) 65 | 66 | //Bind transforms 67 | .def("transform", [](Vector &self, py::function transformer) { 68 | self.transform([transformer](const int size, double* vector) { 69 | transformer(size, py::array_t(size, vector)); 70 | }); 71 | }) 72 | .def("transform", [](Vector &self, Vector& result, py::function transformer) { 73 | self.transform(result, [transformer](const int size, double* vector) { 74 | transformer(size, py::array_t(size, vector)); 75 | }); 76 | }) 77 | 78 | .def("transform", [](Vector &self, Vector* result, py::function transformer) { 79 | self.transform(result, [transformer](const int size, double* vector) { 80 | transformer(size, py::array_t(size, vector)); 81 | }); 82 | }) 83 | .def("transform", [](Vector &self, py::function transformer) { 84 | self.transform([transformer](const int size, double* origVector, double* resultVector) { 85 | transformer(size, py::array_t(size, origVector), py::array_t(size, resultVector)); 86 | }); 87 | }) 88 | .def("transform", [](Vector &self, Vector& result, py::function transformer) { 89 | self.transform(result, [transformer](const int size, double* origVector, double* resultVector) { 90 | transformer(size, py::array_t(size, origVector), py::array_t(size, resultVector)); 91 | }); 92 | }) 93 | .def("transform", [](Vector &self, Vector* result, py::function transformer) { 94 | self.transform(result, [transformer](const int size, double* origVector, double* resultVector) { 95 | transformer(size, py::array_t(size, origVector), py::array_t(size, resultVector)); 96 | }); 97 | }) 98 | 99 | //Bind set size method 100 | .def("setSize", &Vector::setSize) 101 | 102 | .def("distributed", &Vector::distributed) 103 | 104 | .def("dim", &Vector::dim) 105 | 106 | .def("inner_product", (double (Vector::*)(const Vector&) const) &Vector::inner_product) 107 | .def("inner_product", (double (Vector::*)(const Vector*) const) &Vector::inner_product) 108 | 109 | .def("norm", &Vector::norm) 110 | .def("norm2", &Vector::norm2) 111 | .def("normalize", &Vector::normalize) 112 | 113 | .def("plus", (Vector* (Vector::*)(const Vector&) const) &Vector::plus) 114 | .def("plus", (Vector* (Vector::*)(const Vector*) const) &Vector::plus) 115 | .def("plus", [](const Vector& self,const Vector& other,Vector* result) { 116 | self.plus(other,*result); 117 | }) 118 | .def("plus", (void (Vector::*)(const Vector&, Vector&) const) &Vector::plus) 119 | 120 | 121 | .def("plusAx", [](Vector& self, double factor, const Vector& other) { 122 | Vector* result = 0; 123 | self.plusAx(factor, other,result); 124 | return result; 125 | }, py::return_value_policy::automatic) 126 | .def("plusAx", (Vector* (Vector::*)(double,const Vector*)) &Vector::plusAx, py::return_value_policy::automatic) 127 | .def("plusAx", [](const Vector& self, double factor, const Vector& other,Vector* result) { 128 | self.plusAx(factor,other,*result); 129 | }) 130 | .def("plusAx", (void (Vector::*)(double, const Vector&,Vector&) const) &Vector::plusAx) 131 | 132 | 133 | .def("plusEqAx", (void (Vector::*)(double, const Vector&)) &Vector::plusEqAx) 134 | .def("plusEqAx", [](Vector& self, double factor, const Vector* other) { 135 | self.plusEqAx(factor, *other); 136 | }, py::return_value_policy::automatic) 137 | 138 | .def("minus", (Vector* (Vector::*)(const Vector&) const) &Vector::minus) 139 | .def("minus", (Vector* (Vector::*)(const Vector*) const) &Vector::minus) 140 | .def("minus",[](const Vector& self,const Vector& other,Vector* result){ 141 | self.minus(other,*result); 142 | }) 143 | .def("minus", (void (Vector::*)(const Vector&, Vector&) const) &Vector::minus) 144 | 145 | .def("mult", [](const Vector& self, double factor) { 146 | Vector* result = 0; 147 | self.mult(factor,result); 148 | return result; 149 | }, py::return_value_policy::automatic) 150 | .def("mult", [](const Vector& self, double factor, Vector* result) { 151 | self.mult(factor, *result); 152 | }) 153 | .def("mult", [](const Vector& self, double factor, Vector& result) { 154 | self.mult(factor, result); 155 | }) 156 | 157 | .def("item", (const double& (Vector::*)(int) const) &Vector::item) 158 | .def("__getitem__", [](const Vector& self, int i) { 159 | return self(i); 160 | }) 161 | .def("__setitem__", [](Vector& self, int i, double value) { 162 | self.item(i) = value; 163 | }) 164 | .def("__call__", (const double& (Vector::*)(int) const) &Vector::operator()) 165 | .def("__call__", (double& (Vector::*)(int)) &Vector::operator()) 166 | .def("print", &Vector::print) 167 | .def("write", &Vector::write) 168 | .def("read", &Vector::read) 169 | .def("local_read", &Vector::local_read) 170 | .def("getData", [](Vector& self) { 171 | // We provide a view vector, which does not free the memory at its destruction. 172 | py::capsule buffer_handle([](){}); 173 | // Use this if the C++ memory SHOULD be deallocated 174 | // once the Python no longer has a reference to it 175 | // py::capsule buffer_handle(data_buffer, [](void* p){ free(p); }); 176 | 177 | return py::array(bufferInfo(self), buffer_handle); 178 | }) 179 | .def("localMin", &Vector::localMin) 180 | 181 | // TODO: this needs re-naming. confusing with getData. 182 | .def("get_data", [](const Vector& self) { 183 | std::vector data(self.dim()); 184 | for (int i = 0; i < self.dim(); ++i) { 185 | data[i] = self.item(i); 186 | } 187 | return data; 188 | }) 189 | 190 | .def("__del__", [](Vector& self) { self.~Vector(); }); // Destructor 191 | 192 | m.def("getCenterPoint", [](std::vector& points, bool use_centroid) { 193 | return getCenterPoint(points, use_centroid); 194 | }); 195 | 196 | m.def("getCenterPoint", [](std::vector& points, bool use_centroid) { 197 | return getCenterPoint(points, use_centroid); 198 | }); 199 | 200 | m.def("getClosestPoint", [](std::vector& points, Vector* test_point) { 201 | return getClosestPoint(points, test_point); 202 | }); 203 | 204 | m.def("getClosestPoint", [](std::vector& points, Vector test_point) { 205 | return getClosestPoint(points, test_point); 206 | }); 207 | 208 | } 209 | -------------------------------------------------------------------------------- /bindings/pylibROM/linalg/svd/__init__.py: -------------------------------------------------------------------------------- 1 | # To add pure python routines to this module, 2 | # either define/import the python routine in this file. 3 | # This will combine both c++ bindings/pure python routines into this module. 4 | 5 | # For other c++ binding modules, change the module name accordingly. 6 | from _pylibROM.linalg.svd import * -------------------------------------------------------------------------------- /bindings/pylibROM/linalg/svd/pyIncrementalSVD.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "linalg/svd/IncrementalSVD.h" 7 | #include "python_utils/cpp_utils.hpp" 8 | 9 | namespace py = pybind11; 10 | using namespace CAROM; 11 | 12 | 13 | class PyIncrementalSVD : public IncrementalSVD { 14 | 15 | public: 16 | using IncrementalSVD::IncrementalSVD; 17 | 18 | const Matrix* getSpatialBasis() override { 19 | PYBIND11_OVERRIDE(const Matrix*, IncrementalSVD, getSpatialBasis ); 20 | } 21 | 22 | const Matrix* getTemporalBasis() override { 23 | PYBIND11_OVERRIDE(const Matrix*, IncrementalSVD, getTemporalBasis ); 24 | } 25 | 26 | const Vector* getSingularValues() override { 27 | PYBIND11_OVERRIDE(const Vector*, IncrementalSVD, getSingularValues ); 28 | } 29 | 30 | const Matrix* getSnapshotMatrix() override { 31 | PYBIND11_OVERRIDE(const Matrix*, IncrementalSVD, getSnapshotMatrix ); 32 | } 33 | 34 | bool takeSample(double* u_in, bool add_without_increase) override { 35 | PYBIND11_OVERLOAD(bool, IncrementalSVD, takeSample, u_in, add_without_increase); 36 | } 37 | 38 | ~PyIncrementalSVD() override { 39 | std::cout << "Destructor of PyIncrementalSVD is called!" << std::endl; 40 | } 41 | 42 | protected: 43 | 44 | void buildInitialSVD(double* u) override { 45 | PYBIND11_OVERRIDE_PURE(void, IncrementalSVD, buildInitialSVD, u); 46 | } 47 | 48 | void computeBasis() override { 49 | PYBIND11_OVERRIDE_PURE(void, IncrementalSVD, computeBasis, ); 50 | } 51 | 52 | void addLinearlyDependentSample(const Matrix* A, const Matrix* W, const Matrix* sigma) override { 53 | PYBIND11_OVERRIDE_PURE(void, IncrementalSVD, addLinearlyDependentSample, A, W, sigma); 54 | } 55 | 56 | void addNewSample(const Vector* j, const Matrix* A, const Matrix* W, Matrix* sigma) override { 57 | PYBIND11_OVERRIDE_PURE(void, IncrementalSVD, addNewSample, j, A, W, sigma); 58 | } 59 | 60 | }; 61 | 62 | void init_IncrementalSVD(pybind11::module_ &m) { 63 | py::class_(m, "IncrementalSVD") 64 | .def(py::init()) 65 | .def("takeSample", [](IncrementalSVD& self, py::array_t &u_in, bool add_without_increase = false) { 66 | bool result = self.takeSample(getVectorPointer(u_in), add_without_increase); 67 | return result; 68 | }, py::arg("u_in"), py::arg("add_without_increase") = false) 69 | .def("getSpatialBasis", (const Matrix* (IncrementalSVD::*)()) &IncrementalSVD::getSpatialBasis) 70 | .def("getTemporalBasis", (const Matrix* (IncrementalSVD::*)()) &IncrementalSVD::getTemporalBasis) 71 | .def("getSingularValues", (const Vector* (IncrementalSVD::*)()) &IncrementalSVD::getSingularValues) 72 | .def("getSnapshotMatrix", (const Matrix* (IncrementalSVD::*)()) &IncrementalSVD::getSnapshotMatrix) 73 | .def("getDim", (int (IncrementalSVD::*)() const) &IncrementalSVD::getDim) 74 | .def("getMaxNumSamples", (int (IncrementalSVD::*)() const) &IncrementalSVD::getMaxNumSamples) 75 | .def("getNumSamples", (int (IncrementalSVD::*)() const) &IncrementalSVD::getNumSamples); 76 | } 77 | -------------------------------------------------------------------------------- /bindings/pylibROM/linalg/svd/pySVD.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "linalg/svd/SVD.h" 6 | #include "python_utils/cpp_utils.hpp" 7 | 8 | namespace py = pybind11; 9 | using namespace CAROM; 10 | 11 | 12 | class PySVD : public SVD { 13 | public: 14 | using SVD::SVD; // Inherit constructors from the base class 15 | 16 | 17 | const Matrix* getSpatialBasis() override { 18 | PYBIND11_OVERRIDE_PURE(const Matrix*, SVD, getSpatialBasis ); 19 | } 20 | 21 | 22 | const Matrix* getTemporalBasis() override { 23 | PYBIND11_OVERRIDE_PURE(const Matrix*, SVD, getTemporalBasis ); 24 | } 25 | 26 | 27 | const Vector* getSingularValues() override { 28 | PYBIND11_OVERRIDE_PURE(const Vector*, SVD, getSingularValues ); 29 | } 30 | 31 | 32 | const Matrix* getSnapshotMatrix() override { 33 | PYBIND11_OVERRIDE_PURE(const Matrix*, SVD, getSnapshotMatrix ); 34 | } 35 | 36 | 37 | bool takeSample(double* u_in, bool add_without_increase) override { 38 | PYBIND11_OVERLOAD_PURE(bool, SVD, takeSample, u_in, add_without_increase); 39 | } 40 | 41 | 42 | }; 43 | 44 | 45 | void init_SVD(pybind11::module_ &m) { 46 | py::class_(m, "SVD") 47 | .def(py::init()) 48 | .def("takeSample", [](SVD& self, py::array_t &u_in, bool add_without_increase = false) { 49 | return self.takeSample(getVectorPointer(u_in), add_without_increase); 50 | }, py::arg("u_in"), py::arg("add_without_increase") = false) 51 | .def("getDim", (int (SVD::*)() const) &SVD::getDim) 52 | .def("getSpatialBasis", (const Matrix* (SVD::*)()) &SVD::getSpatialBasis) 53 | .def("getTemporalBasis", (const Matrix* (SVD::*)()) &SVD::getTemporalBasis) 54 | .def("getSingularValues", (const Vector* (SVD::*)()) &SVD::getSingularValues) 55 | .def("getSnapshotMatrix", (const Matrix* (SVD::*)()) &SVD::getSnapshotMatrix) 56 | .def("getMaxNumSamples", (int (SVD::*)() const) &SVD::getMaxNumSamples) 57 | .def("getNumSamples", (int (SVD::*)() const) &SVD::getNumSamples) 58 | .def("__del__", [](SVD& self) { 59 | std::cout << "SVD instance is being destroyed" << std::endl; 60 | self.~SVD(); }); 61 | } 62 | -------------------------------------------------------------------------------- /bindings/pylibROM/linalg/svd/pyStaticSVD.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "linalg/svd/StaticSVD.h" 6 | #include "python_utils/cpp_utils.hpp" 7 | 8 | namespace py = pybind11; 9 | using namespace CAROM; 10 | 11 | 12 | class PyStaticSVD : public StaticSVD { 13 | public: 14 | using StaticSVD::StaticSVD; 15 | 16 | 17 | bool takeSample(double* u_in, bool add_without_increase = false) override { 18 | PYBIND11_OVERRIDE(bool, StaticSVD, takeSample, u_in, add_without_increase); 19 | } 20 | 21 | 22 | const Matrix* getSpatialBasis() override { 23 | PYBIND11_OVERRIDE(const Matrix*, StaticSVD, getSpatialBasis); 24 | } 25 | 26 | 27 | const Matrix* getTemporalBasis() override { 28 | PYBIND11_OVERRIDE(const Matrix*, StaticSVD, getTemporalBasis); 29 | } 30 | 31 | 32 | const Vector* getSingularValues() override { 33 | PYBIND11_OVERRIDE(const Vector*, StaticSVD, getSingularValues); 34 | } 35 | 36 | 37 | const Matrix* getSnapshotMatrix() override { 38 | PYBIND11_OVERRIDE(const Matrix*, StaticSVD, getSnapshotMatrix); 39 | } 40 | 41 | 42 | PyStaticSVD(Options options) : StaticSVD(options) {} 43 | static PyStaticSVD* create(Options options) { 44 | return new PyStaticSVD(options); 45 | } 46 | 47 | }; 48 | 49 | 50 | void init_StaticSVD(pybind11::module& m) { 51 | py::class_(m, "StaticSVD") 52 | .def(py::init(&PyStaticSVD::create), py::arg("options")) 53 | .def("takeSample", [](StaticSVD& self, py::array_t &u_in, bool add_without_increase = false) { 54 | bool result = self.takeSample(getVectorPointer(u_in), add_without_increase); 55 | return result; 56 | }, py::arg("u_in"), py::arg("add_without_increase") = false) 57 | .def("getSpatialBasis", (const Matrix* (StaticSVD::*)()) &StaticSVD::getSpatialBasis,py::return_value_policy::reference_internal) 58 | .def("getTemporalBasis", (const Matrix* (StaticSVD::*)()) &StaticSVD::getTemporalBasis,py::return_value_policy::reference_internal) 59 | .def("getSingularValues", (const Vector* (StaticSVD::*)()) &StaticSVD::getSingularValues,py::return_value_policy::reference_internal) 60 | .def("getSnapshotMatrix", (const Matrix* (StaticSVD::*)()) &StaticSVD::getSnapshotMatrix,py::return_value_policy::reference_internal) 61 | .def("getDim", (int (StaticSVD::*)() const) &StaticSVD::getDim) 62 | .def("getMaxNumSamples", (int (StaticSVD::*)() const) &StaticSVD::getMaxNumSamples) 63 | .def("getNumSamples", (int (StaticSVD::*)() const) &StaticSVD::getNumSamples); 64 | 65 | } 66 | 67 | 68 | -------------------------------------------------------------------------------- /bindings/pylibROM/mfem/PointwiseSnapshot.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import mfem.par as mfem 3 | from mpi4py import MPI 4 | 5 | class PointwiseSnapshot: 6 | finder = None 7 | npoints = -1 8 | dims = [-1] * 3 9 | spaceDim = -1 10 | 11 | domainMin = mfem.Vector() 12 | domainMax = mfem.Vector() 13 | xyz = mfem.Vector() 14 | 15 | def __init__(self, sdim, dims_): 16 | self.finder = None 17 | self.spaceDim = sdim 18 | assert((1 < sdim) and (sdim < 4)) 19 | 20 | self.npoints = np.prod(dims_[:self.spaceDim]) 21 | self.dims = np.ones((3,), dtype=int) 22 | self.dims[:self.spaceDim] = dims_[:self.spaceDim] 23 | 24 | self.xyz.SetSize(self.npoints * self.spaceDim) 25 | self.xyz.Assign(0.) 26 | return 27 | 28 | def SetMesh(self, pmesh): 29 | if (self.finder is not None): 30 | self.finder.FreeData() # Free the internal gslib data. 31 | del self.finder 32 | 33 | assert(pmesh.Dimension() == self.spaceDim) 34 | assert(pmesh.SpaceDimension() == self.spaceDim) 35 | 36 | self.domainMin, self.domainMax = pmesh.GetBoundingBox(0) 37 | 38 | h = [0.] * 3 39 | for i in range(self.spaceDim): 40 | h[i] = (self.domainMax[i] - self.domainMin[i]) / float(self.dims[i] - 1) 41 | 42 | rank = pmesh.GetMyRank() 43 | if (rank == 0): 44 | print("PointwiseSnapshot on bounding box from (", 45 | self.domainMin[:self.spaceDim], 46 | ") to (", self.domainMax[:self.spaceDim], ")") 47 | 48 | # TODO(kevin): we might want to re-write this loop in python manner. 49 | xyzData = self.xyz.GetDataArray() 50 | for k in range(self.dims[2]): 51 | pz = self.domainMin[2] + k * h[2] if (self.spaceDim > 2) else 0.0 52 | osk = k * self.dims[0] * self.dims[1] 53 | 54 | for j in range(self.dims[1]): 55 | py = self.domainMin[1] + j * h[1] 56 | osj = (j * self.dims[0]) + osk 57 | 58 | for i in range(self.dims[0]): 59 | px = self.domainMin[0] + i * h[0] 60 | xyzData[i + osj] = px 61 | if (self.spaceDim > 1): xyzData[self.npoints + i + osj] = py 62 | if (self.spaceDim > 2): xyzData[2 * self.npoints + i + osj] = pz 63 | 64 | self.finder = mfem.FindPointsGSLIB(MPI.COMM_WORLD) 65 | # mfem.FindPointsGSLIB() 66 | self.finder.Setup(pmesh) 67 | self.finder.SetL2AvgType(mfem.FindPointsGSLIB.NONE) 68 | return 69 | 70 | def GetSnapshot(self, f, s): 71 | vdim = f.FESpace().GetVDim() 72 | s.SetSize(self.npoints * vdim) 73 | 74 | self.finder.Interpolate(self.xyz, f, s) 75 | 76 | code_out = self.finder.GetCode() 77 | print(type(code_out)) 78 | print(code_out.__dir__()) 79 | 80 | assert(code_out.Size() == self.npoints) 81 | 82 | # Note that Min() and Max() are not defined for Array 83 | #MFEM_VERIFY(code_out.Min() >= 0 && code_out.Max() < 2, ""); 84 | cmin = code_out[0] 85 | cmax = code_out[0] 86 | # TODO(kevin): does this work for mfem array? 87 | for c in code_out: 88 | if (c < cmin): 89 | cmin = c 90 | if (c > cmax): 91 | cmax = c 92 | 93 | assert((cmin >= 0) and (cmax < 2)) 94 | return -------------------------------------------------------------------------------- /bindings/pylibROM/mfem/Utilities.py: -------------------------------------------------------------------------------- 1 | def ComputeCtAB(A, B, C, CtAB): 2 | import _pylibROM.linalg as libROM 3 | from ctypes import c_double 4 | 5 | # determine the mfem module to import. 6 | import inspect, importlib 7 | A_mod_name = inspect.getmodule(A).__name__ 8 | mfem_mode = A_mod_name.split('.')[1][1:] 9 | if (mfem_mode == "ser"): 10 | import mfem.ser as mfem 11 | elif (mfem_mode == "par"): 12 | import mfem.par as mfem 13 | else: 14 | raise ImportError("Matrix A should be from either mfem.ser or mfem.par! A module: %s" % A_mod_name) 15 | 16 | # spatial basis is always distributed regardless of actual MPI initialization. 17 | assert((B.distributed()) and (C.distributed()) and (not CtAB.distributed())) 18 | 19 | num_rows = B.numRows() 20 | num_cols = B.numColumns() 21 | num_rows_A = A.NumRows() 22 | 23 | assert(C.numRows() == num_rows_A) 24 | 25 | Bvec = libROM.Vector(num_rows, False) 26 | BvecData = Bvec.getData() 27 | ABvec = mfem.Vector(num_rows_A) 28 | 29 | AB = libROM.Matrix(num_rows_A, num_cols, True) 30 | ABdata = AB.getData() 31 | 32 | for i in range(num_cols): 33 | B.getColumn(i, Bvec) 34 | A.Mult(mfem.Vector(BvecData, num_rows), ABvec) 35 | ABdata[:, i] = (c_double * ABvec.Size()).from_address(int(ABvec.GetData())) 36 | # for j in range(num_rows_A): 37 | # AB[j, i] = ABvec[j] 38 | 39 | C.transposeMult(AB, CtAB) 40 | return 41 | -------------------------------------------------------------------------------- /bindings/pylibROM/mfem/__init__.py: -------------------------------------------------------------------------------- 1 | # To add pure python routines to this module, 2 | # either define/import the python routine in this file. 3 | # This will combine both c++ bindings/pure python routines into this module. 4 | from _pylibROM.mfem import * 5 | # from .Utilities import ComputeCtAB 6 | # from .PointwiseSnapshot import PointwiseSnapshot -------------------------------------------------------------------------------- /bindings/pylibROM/mfem/pyPointwiseSnapshot.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by sullan2 on 4/20/23. 3 | // 4 | #include 5 | #include "mfem/PointwiseSnapshot.hpp" 6 | #include "python_utils/cpp_utils.hpp" 7 | 8 | namespace py = pybind11; 9 | using namespace mfem; 10 | 11 | void init_mfem_PointwiseSnapshot(pybind11::module_ &m) { 12 | 13 | py::class_(m, "PointwiseSnapshot") 14 | 15 | .def(py::init([](const int sdim, py::array_t &dims){ 16 | return new CAROM::PointwiseSnapshot(sdim, getVectorPointer(dims)); 17 | })) 18 | 19 | .def("SetMesh", [](CAROM::PointwiseSnapshot &self, py::object &pmesh) { 20 | self.SetMesh(extractSwigPtr(pmesh)); 21 | }) 22 | 23 | .def("GetSnapshot", [](CAROM::PointwiseSnapshot &self, py::object &f, py::object &s) { 24 | ParGridFunction *fptr = extractSwigPtr(f); 25 | Vector *sptr = extractSwigPtr(s); 26 | self.GetSnapshot(*fptr, *sptr); 27 | }) 28 | 29 | //TODO: needed explicitly? 30 | .def("__del__", [](CAROM::PointwiseSnapshot& self) { self.~PointwiseSnapshot(); }); // Destructor 31 | 32 | } 33 | -------------------------------------------------------------------------------- /bindings/pylibROM/mfem/pySampleMesh.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by sullan2 on 4/20/23. 3 | // 4 | #include 5 | #include "mfem/SampleMesh.hpp" 6 | #include "python_utils/cpp_utils.hpp" 7 | 8 | namespace py = pybind11; 9 | using namespace mfem; 10 | 11 | void init_mfem_SampleMesh(pybind11::module_ &m) { 12 | 13 | m.def("SampleVisualization", [](py::object &pmesh, std::set const& elems, 14 | std::set const& intElems, std::set const& faces, 15 | std::set const& edges, std::set const& vertices, 16 | std::string const& filename, py::object &elemCount, 17 | double elementScaling){ 18 | ParMesh *pmeshPtr = extractSwigPtr(pmesh); 19 | Vector *elemCountPtr = nullptr; 20 | if (!elemCount.is_none()) 21 | elemCountPtr = extractSwigPtr(elemCount); 22 | 23 | CAROM::SampleVisualization(pmeshPtr, elems, intElems, faces, edges, vertices, 24 | filename, elemCountPtr, elementScaling); 25 | }, 26 | py::arg("pmesh"), py::arg("elems"), py::arg("intElems"), py::arg("faces"), 27 | py::arg("edges"), py::arg("vertices"), py::arg("filename"), 28 | py::arg("elemCount") = py::none(), py::arg("elementScaling") = 1.0); 29 | 30 | py::class_(m, "SampleMeshManager") 31 | 32 | .def(py::init([](py::list &fespace_, std::string visFilename, double visScale){ 33 | std::vector fespacePtr(0); 34 | for (py::handle obj : fespace_) 35 | fespacePtr.push_back(extractSwigPtr(obj)); 36 | return new CAROM::SampleMeshManager(fespacePtr, visFilename, visScale); 37 | }), 38 | py::arg("fespace_"), py::arg("visFilename") = "", py::arg("visScale") = 1.0) 39 | 40 | .def("RegisterSampledVariable", &CAROM::SampleMeshManager::RegisterSampledVariable) 41 | 42 | .def("ConstructSampleMesh", &CAROM::SampleMeshManager::ConstructSampleMesh) 43 | 44 | .def("GatherDistributedMatrixRows", &CAROM::SampleMeshManager::GatherDistributedMatrixRows) 45 | 46 | .def("GetSampleFESpace", [](CAROM::SampleMeshManager& self, const int space, py::object &spfespace){ 47 | ParFiniteElementSpace *spfes_target = self.GetSampleFESpace(space); 48 | 49 | // deep copy of the spfes_target. 50 | void *spfes_address = extractSwigPtr(spfespace); 51 | ParFiniteElementSpace *spfes = new (spfes_address) ParFiniteElementSpace(*spfes_target); 52 | }) 53 | 54 | .def("GetSampleMesh", [](CAROM::SampleMeshManager& self, py::object &sppmesh){ 55 | ParMesh *sppmesh_target = self.GetSampleMesh(); 56 | 57 | // deep copy of the spfes_target. 58 | void *sppmesh_address = extractSwigPtr(sppmesh); 59 | ParMesh *sample_pmesh = new (sppmesh_address) ParMesh(*sppmesh_target); 60 | }) 61 | 62 | .def("GetNumVarSamples", &CAROM::SampleMeshManager::GetNumVarSamples) 63 | 64 | .def("GetSampledValues", [](CAROM::SampleMeshManager &self, const std::string variable, py::object &v, CAROM::Vector &s){ 65 | Vector *v_ptr = extractSwigPtr(v); 66 | self.GetSampledValues(variable, *v_ptr, s); 67 | }) 68 | 69 | .def("GetSampleElements", &CAROM::SampleMeshManager::GetSampleElements) 70 | 71 | .def("WriteVariableSampleMap", &CAROM::SampleMeshManager::WriteVariableSampleMap) 72 | 73 | //TODO: needed explicitly? 74 | .def("__del__", [](CAROM::SampleMeshManager& self){ self.~SampleMeshManager(); }); // Destructor 75 | 76 | py::class_(m, "SampleDOFSelector") 77 | 78 | .def(py::init<>()) 79 | 80 | .def("ReadMapFromFile", &CAROM::SampleDOFSelector::ReadMapFromFile) 81 | 82 | .def("GetSampledValues", [](CAROM::SampleDOFSelector &self, const std::string variable, py::object &v, CAROM::Vector &s){ 83 | Vector *v_ptr = extractSwigPtr(v); 84 | self.GetSampledValues(variable, *v_ptr, s); 85 | }); 86 | 87 | } 88 | -------------------------------------------------------------------------------- /bindings/pylibROM/mfem/pyUtilities.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by sullan2 on 4/20/23. 3 | // 4 | #include 5 | #include "mfem/Utilities.hpp" 6 | #include "python_utils/cpp_utils.hpp" 7 | 8 | namespace py = pybind11; 9 | using namespace mfem; 10 | 11 | void init_mfem_Utilities(pybind11::module_ &m) { 12 | 13 | m.def("ComputeCtAB", [](py::object &A, 14 | const CAROM::Matrix& B, 15 | const CAROM::Matrix& C, 16 | CAROM::Matrix& CtAB){ 17 | HypreParMatrix *Aptr = extractSwigPtr(A); 18 | CAROM::ComputeCtAB(*Aptr, B, C, CtAB); 19 | }); 20 | 21 | m.def("ComputeCtAB_vec", [](py::object &A, 22 | py::object &B, 23 | const CAROM::Matrix& C, 24 | CAROM::Vector& CtAB_vec){ 25 | HypreParMatrix *Aptr = extractSwigPtr(A); 26 | HypreParVector *Bptr = extractSwigPtr(B); 27 | CAROM::ComputeCtAB_vec(*Aptr, *Bptr, C, CtAB_vec); 28 | }); 29 | 30 | } 31 | -------------------------------------------------------------------------------- /bindings/pylibROM/pylibROM.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "CAROM_config.h" 4 | #include "pylibROM_config.h" 5 | 6 | // check that libROM has MFEM if pylibROM is using MFEM 7 | #ifdef PYLIBROM_HAS_MFEM 8 | // temporarily disabled until libROM upstream adds this option 9 | // #ifndef CAROM_HAS_MFEM 10 | // #error "libROM was not compiled with MFEM support" 11 | // #endif 12 | #endif 13 | 14 | namespace py = pybind11; 15 | 16 | //linalg 17 | void init_vector(pybind11::module_ &); 18 | void init_matrix(pybind11::module_ &); 19 | void init_BasisGenerator(pybind11::module_ &); 20 | void init_BasisWriter(pybind11::module_ &); 21 | void init_BasisReader(pybind11::module_ &); 22 | void init_Options(pybind11::module_ &m); 23 | void init_NNLSSolver(pybind11::module_ &m); 24 | 25 | 26 | //linalg/svd 27 | void init_SVD(pybind11::module_ &m); 28 | void init_StaticSVD(pybind11::module& m); 29 | void init_IncrementalSVD(pybind11::module_ &m); 30 | 31 | //algo 32 | void init_DMD(pybind11::module_ &); 33 | void init_ParametricDMD(pybind11::module_ &m); 34 | void init_NonuniformDMD(pybind11::module_ &m); 35 | void init_AdaptiveDMD(pybind11::module_ &m); 36 | 37 | //algo/manifold_interp 38 | void init_Interpolator(pybind11::module_ &); 39 | void init_VectorInterpolator(pybind11::module_ &); 40 | void init_MatrixInterpolator(pybind11::module_ &); 41 | 42 | //algo/greedy 43 | void init_GreedySampler(pybind11::module_ &m); 44 | void init_GreedyCustomSampler(pybind11::module_ &m); 45 | void init_GreedyRandomSampler(pybind11::module_ &m); 46 | 47 | //hyperreduction 48 | void init_DEIM(pybind11::module_ &m); 49 | void init_GNAT(pybind11::module_ &m); 50 | void init_QDEIM(pybind11::module_ &m); 51 | void init_S_OPT(pybind11::module_ &m); 52 | void init_STSampling(pybind11::module_ &m); 53 | void init_Utilities(pybind11::module_ &m); 54 | 55 | //utils 56 | void init_mpi_utils(pybind11::module_ &m); 57 | void init_Database(pybind11::module_ &m); 58 | void init_HDFDatabase(pybind11::module_ &m); 59 | void init_HDFDatabaseMPIO(pybind11::module_ &m); 60 | void init_CSVDatabase(pybind11::module_ &m); 61 | 62 | #ifdef PYLIBROM_HAS_MFEM 63 | //mfem 64 | void init_mfem_Utilities(pybind11::module_ &m); 65 | void init_mfem_PointwiseSnapshot(pybind11::module_ &m); 66 | void init_mfem_SampleMesh(pybind11::module_ &m); 67 | #endif 68 | 69 | PYBIND11_MODULE(_pylibROM, m) { 70 | py::module utils = m.def_submodule("utils"); 71 | init_mpi_utils(utils); 72 | init_Database(utils); 73 | init_HDFDatabase(utils); 74 | init_HDFDatabaseMPIO(utils); 75 | init_CSVDatabase(utils); 76 | 77 | py::module linalg = m.def_submodule("linalg"); 78 | init_vector(linalg); 79 | init_matrix(linalg); 80 | init_BasisGenerator(linalg); 81 | init_BasisWriter(linalg); 82 | init_BasisReader(linalg); 83 | init_Options(linalg); 84 | init_NNLSSolver(linalg); 85 | 86 | py::module svd = linalg.def_submodule("svd"); 87 | init_SVD(svd); 88 | init_StaticSVD(svd); 89 | init_IncrementalSVD(svd); 90 | 91 | py::module algo = m.def_submodule("algo"); 92 | init_DMD(algo); 93 | init_ParametricDMD(algo); 94 | init_AdaptiveDMD(algo); 95 | init_NonuniformDMD(algo); 96 | 97 | py::module manifold_interp = algo.def_submodule("manifold_interp"); 98 | init_Interpolator(manifold_interp); 99 | init_VectorInterpolator(manifold_interp); 100 | init_MatrixInterpolator(manifold_interp); 101 | 102 | py::module greedy = algo.def_submodule("greedy"); 103 | init_GreedySampler(greedy); 104 | init_GreedyCustomSampler(greedy); 105 | init_GreedyRandomSampler(greedy); 106 | 107 | py::module hyperreduction = m.def_submodule("hyperreduction"); 108 | init_DEIM(hyperreduction); 109 | init_GNAT(hyperreduction); 110 | init_QDEIM(hyperreduction); 111 | init_S_OPT(hyperreduction); 112 | init_STSampling(hyperreduction); 113 | init_Utilities(hyperreduction); 114 | 115 | #ifdef PYLIBROM_HAS_MFEM 116 | py::module mfem = m.def_submodule("mfem"); 117 | init_mfem_Utilities(mfem); 118 | init_mfem_PointwiseSnapshot(mfem); 119 | init_mfem_SampleMesh(mfem); 120 | #endif 121 | 122 | // py::module python_utils = m.def_submodule("python_utils"); 123 | } 124 | 125 | /* 126 | void init_DMD(pybind11::module_ &); 127 | 128 | PYBIND11_MODULE(pylibROM, m) { 129 | py::module algo = m.def_submodule("algo"); 130 | init_DMD(algo); 131 | } 132 | */ 133 | -------------------------------------------------------------------------------- /bindings/pylibROM/pylibROM_config.h.in: -------------------------------------------------------------------------------- 1 | #ifndef PYLIBROM_CONFIG_H_ 2 | #define PYLIBROM_CONFIG_H_ 3 | 4 | #cmakedefine PYLIBROM_HAS_MFEM 5 | 6 | #endif 7 | -------------------------------------------------------------------------------- /bindings/pylibROM/python_utils/StopWatch.py: -------------------------------------------------------------------------------- 1 | # pyMFEM does not provide mfem::StopWatch. 2 | # there is not really a similar stopwatch package in python.. (seriously?) 3 | import time 4 | 5 | class StopWatch: 6 | duration = 0.0 7 | start_time = 0.0 8 | stop_time = 0.0 9 | running = False 10 | 11 | def __init__(self): 12 | self.Reset() 13 | return 14 | 15 | def Start(self): 16 | assert(not self.running) 17 | self.start_time = time.time() 18 | self.running = True 19 | return 20 | 21 | def Stop(self): 22 | assert(self.running) 23 | self.stop_time = time.time() 24 | self.duration += self.stop_time - self.start_time 25 | self.running = False 26 | return 27 | 28 | def Reset(self): 29 | self.duration = 0.0 30 | self.start_time = 0.0 31 | self.stop_time = 0.0 32 | self.running = False 33 | return 34 | -------------------------------------------------------------------------------- /bindings/pylibROM/python_utils/__init__.py: -------------------------------------------------------------------------------- 1 | # To add pure python routines to this module, 2 | # either define/import the python routine in this file. 3 | # This will combine both c++ bindings/pure python routines into this module. 4 | from .StopWatch import StopWatch 5 | 6 | def swigdouble2numpyarray(u_swig, u_size): 7 | from ctypes import c_double 8 | from numpy import array 9 | return array((c_double * u_size).from_address(int(u_swig)), copy=False) -------------------------------------------------------------------------------- /bindings/pylibROM/python_utils/cpp_utils.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by sullan2 on 4/20/23. 3 | // 4 | 5 | #ifndef CPP_UTILS_HPP 6 | #define CPP_UTILS_HPP 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | namespace py = pybind11; 13 | 14 | template 15 | T* getPointer(py::array_t &u_in) 16 | { 17 | py::buffer_info buf_info = u_in.request(); 18 | // If it is 1D array, we should ensure that the memory is contiguous. 19 | if ((buf_info.ndim == 1) && (buf_info.strides[0] != sizeof(T))) 20 | { 21 | std::string msg = "Input numpy array must have a contiguous memory! - "; 22 | msg += std::to_string(buf_info.strides[0]) + "\n"; 23 | throw std::runtime_error(msg.c_str()); 24 | } 25 | 26 | return static_cast(buf_info.ptr); 27 | } 28 | 29 | template 30 | ssize_t getDim(py::array_t &u_in) 31 | { 32 | return u_in.request().ndim; 33 | } 34 | 35 | template 36 | T* getVectorPointer(py::array_t &u_in) 37 | { 38 | py::buffer_info buf_info = u_in.request(); 39 | // If it is 1D array, we should ensure that the memory is contiguous. 40 | if (buf_info.ndim != 1) 41 | { 42 | throw std::runtime_error("Input array must be 1-dimensional!\n"); 43 | } 44 | else if (buf_info.strides[0] != sizeof(T)) 45 | { 46 | std::string msg = "Input numpy array must have a contiguous memory! - "; 47 | msg += std::to_string(buf_info.strides[0]) + "\n"; 48 | throw std::runtime_error(msg.c_str()); 49 | } 50 | 51 | return static_cast(buf_info.ptr); 52 | } 53 | 54 | template 55 | py::buffer_info 56 | get1DArrayBufferInfo(T *ptr, const int nelem) 57 | { 58 | return py::buffer_info( 59 | ptr, /* Pointer to buffer */ 60 | sizeof(T), /* Size of one scalar */ 61 | py::format_descriptor::format(), /* Python struct-style format descriptor */ 62 | 1, /* Number of dimensions */ 63 | { nelem }, /* Buffer dimensions */ 64 | { sizeof(T) } /* Strides (in bytes) for each index */ 65 | ); 66 | } 67 | 68 | template 69 | py::capsule 70 | get1DArrayBufferHandle(T *ptr, const bool free_when_done=false) 71 | { 72 | if (free_when_done) 73 | return py::capsule(ptr, [](void *f){ 74 | T *T_ptr = reinterpret_cast(f); 75 | delete[] T_ptr; 76 | }); 77 | else 78 | return py::capsule([](){}); 79 | } 80 | 81 | template 82 | py::array_t 83 | get1DArrayFromPtr(T *ptr, const int nelem, bool free_when_done=false) 84 | { 85 | // if empty array, no need to free when done. 86 | free_when_done = free_when_done && (nelem > 0); 87 | return py::array(get1DArrayBufferInfo(ptr, nelem), 88 | get1DArrayBufferHandle(ptr, free_when_done)); 89 | } 90 | 91 | template 92 | T* 93 | extractSwigPtr(const py::handle &swig_target) 94 | { 95 | // On python, swig_target.this.__int__() returns the memory address of the wrapped c++ object pointer. 96 | // We execute the same command here in the c++ side, where the memory address is given as py::object. 97 | // The returned py::object is simply cast as std::uintptr_t, which is then cast into a c++ object type we want. 98 | std::uintptr_t temp = swig_target.attr("this").attr("__int__")().cast(); 99 | return reinterpret_cast(temp); 100 | } 101 | 102 | #endif 103 | -------------------------------------------------------------------------------- /bindings/pylibROM/utils/__init__.py: -------------------------------------------------------------------------------- 1 | # To add pure python routines to this module, 2 | # either define/import the python routine in this file. 3 | # This will combine both c++ bindings/pure python routines into this module. 4 | 5 | # For other c++ binding modules, change the module name accordingly. 6 | from _pylibROM.utils import * -------------------------------------------------------------------------------- /bindings/pylibROM/utils/mpi_utils.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by sullan2 on 4/20/23. 3 | // 4 | #include 5 | // #include 6 | // #include 7 | #include 8 | 9 | #include "utils/mpi_utils.h" 10 | 11 | #include "mpicomm.hpp" 12 | 13 | namespace py = pybind11; 14 | using namespace CAROM; 15 | 16 | void init_mpi_utils(pybind11::module_ &m) { 17 | // import the mpi4py API 18 | if (import_mpi4py() < 0) { 19 | throw std::runtime_error("Could not load mpi4py API."); 20 | } 21 | // m.def("split_dimension", (int ()(const int, const mpi4py_comm&)) &split_dimension); 22 | m.def("split_dimension", [](const int dim, const mpi4py_comm &comm) { 23 | return split_dimension(dim, comm.value); 24 | }); 25 | // m.def("get_global_offsets", (int ()(const int, const MPI_Comm&)) &get_global_offsets); 26 | m.def("get_global_offsets", [](const int local_dim, const mpi4py_comm &comm) { 27 | std::vector offsets; 28 | int global_dim = get_global_offsets(local_dim, offsets, comm.value); 29 | return py::make_tuple(global_dim, offsets); 30 | }); 31 | } 32 | -------------------------------------------------------------------------------- /bindings/pylibROM/utils/mpicomm.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "mpi.h" 7 | #include 8 | 9 | struct mpi4py_comm { 10 | mpi4py_comm() = default; 11 | mpi4py_comm(MPI_Comm value) : value(value) {} 12 | operator MPI_Comm () { return value; } 13 | 14 | MPI_Comm value; 15 | }; 16 | 17 | namespace pybind11 { 18 | namespace detail { 19 | template <> struct type_caster { 20 | public: 21 | PYBIND11_TYPE_CASTER(mpi4py_comm, _("mpi4py_comm")); 22 | 23 | // Python -> C++ 24 | bool load(handle src, bool) { 25 | PyObject *py_src = src.ptr(); 26 | 27 | // Check that we have been passed an mpi4py communicator 28 | if (PyObject_TypeCheck(py_src, &PyMPIComm_Type)) { 29 | // Convert to regular MPI communicator 30 | value.value = *PyMPIComm_Get(py_src); 31 | } else { 32 | return false; 33 | } 34 | 35 | return !PyErr_Occurred(); 36 | } 37 | 38 | // C++ -> Python 39 | static handle cast(mpi4py_comm src, 40 | return_value_policy /* policy */, 41 | handle /* parent */) 42 | { 43 | if (src == MPI_COMM_NULL) { 44 | return Py_None; 45 | } 46 | 47 | // Create an mpi4py handle 48 | return PyMPIComm_New(src.value); 49 | } 50 | }; 51 | } 52 | } // namespace pybind11::detail -------------------------------------------------------------------------------- /bindings/pylibROM/utils/pyCSVDatabase.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by sullan2 on 4/20/23. 3 | // 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "utils/CSVDatabase.h" 9 | #include "utils/pyDatabase.hpp" 10 | #include "python_utils/cpp_utils.hpp" 11 | 12 | namespace py = pybind11; 13 | using namespace CAROM; 14 | 15 | class PyCSVDatabase : public PyDerivedDatabase { 16 | public: 17 | using PyDerivedDatabase::PyDerivedDatabase; 18 | 19 | // somehow this function is not virtual on c++ side. technically does not need this trampoline? 20 | void 21 | getStringVector( 22 | const std::string& file_name, 23 | std::vector &data, 24 | bool append = false) 25 | { 26 | PYBIND11_OVERRIDE( 27 | void, /* Return type */ 28 | CSVDatabase, /* Child class */ 29 | getStringVector, /* Name of function in C++ (must match Python name) */ 30 | file_name, data, append /* Argument(s) */ 31 | ); 32 | } 33 | 34 | // somehow this function is not virtual on c++ side. technically does not need this trampoline? 35 | int 36 | getLineCount( 37 | const std::string& file_name) 38 | { 39 | PYBIND11_OVERRIDE( 40 | int, /* Return type */ 41 | CSVDatabase, /* Child class */ 42 | getLineCount, /* Name of function in C++ (must match Python name) */ 43 | file_name /* Argument(s) */ 44 | ); 45 | } 46 | 47 | }; 48 | 49 | void init_CSVDatabase(pybind11::module_ &m) { 50 | 51 | py::class_ csvdb(m, "CSVDatabase"); 52 | 53 | // Constructor 54 | csvdb.def(py::init<>()); 55 | 56 | csvdb.def("create", [](CSVDatabase &self, const std::string& file_name, 57 | const mpi4py_comm comm) -> bool { 58 | return self.create(file_name, comm.value); 59 | }, py::arg("file_name"), py::arg("comm")); 60 | csvdb.def("create", [](CSVDatabase &self, const std::string& file_name) -> bool { 61 | return self.create(file_name, MPI_COMM_NULL); 62 | }, py::arg("file_name")); 63 | csvdb.def("open", [](CSVDatabase &self, const std::string& file_name, 64 | const std::string &type, const mpi4py_comm comm) -> bool { 65 | return self.open(file_name, type, comm.value); 66 | }, py::arg("file_name"), py::arg("type"), py::arg("comm")); 67 | csvdb.def("open", [](CSVDatabase &self, const std::string& file_name, 68 | const std::string &type) -> bool { 69 | return self.open(file_name, type, MPI_COMM_NULL); 70 | }, py::arg("file_name"), py::arg("type")); 71 | csvdb.def("close", &CSVDatabase::close); 72 | 73 | // TODO(kevin): finish binding of member functions. 74 | csvdb.def("putDoubleArray", []( 75 | CSVDatabase &self, const std::string& key, py::array_t &data, int nelements, bool distributed = false) 76 | { 77 | self.putDoubleArray(key, getVectorPointer(data), nelements, distributed); 78 | }, py::arg("key"), py::arg("data"), py::arg("nelements"), py::arg("distributed") = false); 79 | csvdb.def("putDoubleVector", &CSVDatabase::putDoubleVector, py::arg("key"), py::arg("data"), py::arg("nelements"), py::arg("distributed") = false); 80 | csvdb.def("putInteger", &CSVDatabase::putInteger); 81 | csvdb.def("putIntegerArray", []( 82 | CSVDatabase &self, const std::string& key, py::array_t &data, int nelements, bool distributed = false) 83 | { 84 | self.putIntegerArray(key, getVectorPointer(data), nelements); 85 | }, py::arg("key"), py::arg("data"), py::arg("nelements"), py::arg("distributed") = false); 86 | 87 | csvdb.def("getIntegerArray", []( 88 | CSVDatabase &self, const std::string& key, int nelements) 89 | { 90 | int *dataptr = new int[nelements]; 91 | self.getIntegerArray(key, dataptr, nelements); 92 | return get1DArrayFromPtr(dataptr, nelements, true); 93 | }); 94 | 95 | csvdb.def("getIntegerVector", []( 96 | CSVDatabase &self, const std::string& key, bool append) 97 | { 98 | std::vector *datavec = new std::vector; 99 | self.getIntegerVector(key, *datavec, append); 100 | return get1DArrayFromPtr(datavec->data(), datavec->size(), true); 101 | }, 102 | py::arg("key"), py::arg("append") = false); 103 | 104 | csvdb.def("getDoubleArray", []( 105 | CSVDatabase &self, const std::string& key, int nelements) 106 | { 107 | double *dataptr = new double[nelements]; 108 | self.getDoubleArray(key, dataptr, nelements); 109 | return get1DArrayFromPtr(dataptr, nelements, true); 110 | }); 111 | 112 | csvdb.def("getDoubleArray", []( 113 | CSVDatabase &self, const std::string& key, int nelements, const std::vector& idx) 114 | { 115 | double *dataptr = new double[nelements]; 116 | self.getDoubleArray(key, dataptr, nelements, idx); 117 | return get1DArrayFromPtr(dataptr, nelements, true); 118 | }); 119 | 120 | csvdb.def("getDoubleArray", []( 121 | CSVDatabase &self, const std::string& key, int nelements, 122 | int offset, int block_size, int stride) 123 | { 124 | double *dataptr = new double[nelements]; 125 | self.getDoubleArray(key, dataptr, nelements, offset, block_size, stride); 126 | return get1DArrayFromPtr(dataptr, nelements, true); 127 | }); 128 | 129 | csvdb.def("getDoubleVector", []( 130 | CSVDatabase &self, const std::string& key, bool append) 131 | { 132 | std::vector *datavec = new std::vector(); 133 | self.getDoubleVector(key, *datavec, append); 134 | return get1DArrayFromPtr(datavec->data(), datavec->size(), true); 135 | }, 136 | py::arg("key"), py::arg("append") = false); 137 | 138 | csvdb.def("getDoubleArraySize", &CSVDatabase::getDoubleArraySize); 139 | 140 | csvdb.def("getStringVector", []( 141 | CSVDatabase &self, const std::string& file_name, bool append) 142 | { 143 | std::vector data; 144 | self.getStringVector(file_name, data, append); 145 | return py::cast(data); 146 | }, py::arg("file_name"), py::arg("append") = false); 147 | 148 | csvdb.def("getLineCount", &CSVDatabase::getLineCount); 149 | 150 | } 151 | 152 | -------------------------------------------------------------------------------- /bindings/pylibROM/utils/pyDatabase.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by sullan2 on 4/20/23. 3 | // 4 | #include 5 | #include 6 | // #include 7 | #include 8 | #include "utils/Database.h" 9 | #include "utils/pyDatabase.hpp" 10 | 11 | namespace py = pybind11; 12 | using namespace CAROM; 13 | 14 | void init_Database(pybind11::module_ &m) { 15 | 16 | py::class_> db(m, "Database"); 17 | 18 | // Constructor 19 | db.def(py::init<>()); 20 | 21 | py::enum_(db, "formats") 22 | .value("HDF5", Database::formats::HDF5) 23 | .value("CSV", Database::formats::CSV) 24 | .value("HDF5_MPIO", Database::formats::HDF5_MPIO) 25 | .export_values(); 26 | 27 | // https://github.com/pybind/pybind11/issues/2351 28 | //db.def("create", &Database::create); 29 | // // TODO(kevin): finish binding of member functions. 30 | db.def("getInteger", []( 31 | Database &self, const std::string& key) 32 | { 33 | int data; 34 | self.getInteger(key, data); 35 | return data; 36 | }); 37 | } 38 | -------------------------------------------------------------------------------- /bindings/pylibROM/utils/pyHDFDatabase.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by sullan2 on 4/20/23. 3 | // 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "utils/HDFDatabase.h" 9 | #include "utils/pyDatabase.hpp" 10 | #include "python_utils/cpp_utils.hpp" 11 | 12 | namespace py = pybind11; 13 | using namespace CAROM; 14 | 15 | void init_HDFDatabase(pybind11::module_ &m) { 16 | 17 | py::class_> hdfdb(m, "HDFDatabase"); 18 | 19 | // Constructor 20 | hdfdb.def(py::init<>()); 21 | 22 | hdfdb.def("create", [](HDFDatabase &self, const std::string& file_name, 23 | const mpi4py_comm &comm) -> bool { 24 | return self.create(file_name, comm.value); 25 | }); 26 | hdfdb.def("create", [](HDFDatabase &self, const std::string& file_name) -> bool { 27 | return self.create(file_name, MPI_COMM_NULL); 28 | }); 29 | hdfdb.def("open", [](HDFDatabase &self, const std::string& file_name, 30 | const std::string &type, const mpi4py_comm &comm) -> bool { 31 | return self.open(file_name, type, comm.value); 32 | }); 33 | hdfdb.def("open", [](HDFDatabase &self, const std::string& file_name, 34 | const std::string &type) -> bool { 35 | return self.open(file_name, type, MPI_COMM_NULL); 36 | }); 37 | hdfdb.def("close", &HDFDatabase::close); 38 | 39 | // TODO(kevin): finish binding of member functions. 40 | hdfdb.def("putDoubleArray", []( 41 | HDFDatabase &self, const std::string& key, py::array_t &data, int nelements, bool distributed = false) 42 | { 43 | self.putDoubleArray(key, getVectorPointer(data), nelements, distributed); 44 | }, py::arg("key"), py::arg("data"), py::arg("nelements"), py::arg("distributed") = false); 45 | hdfdb.def("putDoubleVector", &HDFDatabase::putDoubleVector, py::arg("key"), py::arg("data"), py::arg("nelements"), py::arg("distributed") = false); 46 | 47 | hdfdb.def("putInteger", &HDFDatabase::putInteger); 48 | hdfdb.def("putIntegerArray", []( 49 | HDFDatabase &self, const std::string& key, py::array_t &data, int nelements, bool distributed = false) 50 | { 51 | self.putIntegerArray(key, getVectorPointer(data), nelements); 52 | }, py::arg("key"), py::arg("data"), py::arg("nelements"), py::arg("distributed") = false); 53 | 54 | hdfdb.def("getIntegerArray", []( 55 | HDFDatabase &self, const std::string& key, int nelements) 56 | { 57 | int *dataptr = new int[nelements]; 58 | self.getIntegerArray(key, dataptr, nelements); 59 | return get1DArrayFromPtr(dataptr, nelements, true); 60 | }); 61 | 62 | hdfdb.def("getDoubleArray", []( 63 | HDFDatabase &self, const std::string& key, int nelements) 64 | { 65 | double *dataptr = new double[nelements]; 66 | self.getDoubleArray(key, dataptr, nelements); 67 | return get1DArrayFromPtr(dataptr, nelements, true); 68 | }); 69 | 70 | hdfdb.def("getDoubleArray", []( 71 | HDFDatabase &self, const std::string& key, int nelements, const std::vector& idx) 72 | { 73 | double *dataptr = new double[nelements]; 74 | self.getDoubleArray(key, dataptr, nelements, idx); 75 | return get1DArrayFromPtr(dataptr, nelements, true); 76 | }); 77 | 78 | hdfdb.def("getDoubleArray", []( 79 | HDFDatabase &self, const std::string& key, int nelements, 80 | int offset, int block_size, int stride) 81 | { 82 | double *dataptr = new double[nelements]; 83 | self.getDoubleArray(key, dataptr, nelements, offset, block_size, stride); 84 | return get1DArrayFromPtr(dataptr, nelements, true); 85 | }); 86 | 87 | hdfdb.def("getDoubleArraySize", &HDFDatabase::getDoubleArraySize); 88 | 89 | // hdfdb.def("__del__", [](HDFDatabase& self) { self.~HDFDatabase(); }); // Destructor 90 | 91 | } 92 | 93 | -------------------------------------------------------------------------------- /bindings/pylibROM/utils/pyHDFDatabaseMPIO.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "utils/HDFDatabaseMPIO.h" 6 | #include "utils/pyDatabase.hpp" 7 | #include "python_utils/cpp_utils.hpp" 8 | #include "CAROM_config.h" 9 | 10 | 11 | namespace py = pybind11; 12 | using namespace CAROM; 13 | 14 | class PyHDFDatabaseMPIO : public PyDerivedDatabase { 15 | public: 16 | using PyDerivedDatabase::PyDerivedDatabase; 17 | 18 | }; 19 | 20 | 21 | void init_HDFDatabaseMPIO(pybind11::module_ &m) { 22 | 23 | py::class_> hdfdb(m, "HDFDatabaseMPIO"); 24 | 25 | // Constructor 26 | hdfdb.def(py::init<>()); 27 | 28 | #if HDF5_IS_PARALLEL 29 | hdfdb.def("create", [](HDFDatabaseMPIO &self, const std::string& file_name, 30 | const mpi4py_comm &comm) -> bool { 31 | return self.create(file_name, comm.value); 32 | }); 33 | hdfdb.def("create", [](HDFDatabaseMPIO &self, const std::string& file_name) -> bool { 34 | return self.create(file_name, MPI_COMM_NULL); 35 | }); 36 | hdfdb.def("open", [](HDFDatabaseMPIO &self, const std::string& file_name, 37 | const std::string &type, const mpi4py_comm &comm) -> bool { 38 | return self.open(file_name, type, comm.value); 39 | }); 40 | hdfdb.def("close", &HDFDatabaseMPIO::close); 41 | 42 | // TODO(kevin): finish binding of member functions. 43 | hdfdb.def("putDoubleArray", []( 44 | HDFDatabaseMPIO &self, const std::string& key, py::array_t &data, int nelements, bool distributed = false) 45 | { 46 | self.putDoubleArray(key, getVectorPointer(data), nelements); 47 | }, py::arg("key"), py::arg("data"), py::arg("nelements"), py::arg("distributed") = false); 48 | hdfdb.def("putDoubleVector", &HDFDatabaseMPIO::putDoubleVector, py::arg("key"), py::arg("data"), py::arg("nelements"), py::arg("distributed") = false); 49 | 50 | hdfdb.def("putInteger", &HDFDatabaseMPIO::putInteger); 51 | hdfdb.def("putIntegerArray", []( 52 | HDFDatabaseMPIO &self, const std::string& key, py::array_t &data, int nelements, bool distributed = false) 53 | { 54 | self.putIntegerArray(key, getVectorPointer(data), nelements); 55 | }, py::arg("key"), py::arg("data"), py::arg("nelements"), py::arg("distributed") = false); 56 | 57 | hdfdb.def("getIntegerArray", []( 58 | HDFDatabaseMPIO &self, const std::string& key, int nelements) 59 | { 60 | int *dataptr = new int[nelements]; 61 | self.getIntegerArray(key, dataptr, nelements); 62 | return get1DArrayFromPtr(dataptr, nelements, true); 63 | }); 64 | 65 | hdfdb.def("getDoubleArray", []( 66 | HDFDatabaseMPIO &self, const std::string& key, int nelements) 67 | { 68 | double *dataptr = new double[nelements]; 69 | self.getDoubleArray(key, dataptr, nelements); 70 | return get1DArrayFromPtr(dataptr, nelements, true); 71 | }); 72 | 73 | hdfdb.def("getDoubleArray", []( 74 | HDFDatabaseMPIO &self, const std::string& key, int nelements, const std::vector& idx) 75 | { 76 | double *dataptr = new double[nelements]; 77 | self.getDoubleArray(key, dataptr, nelements, idx); 78 | return get1DArrayFromPtr(dataptr, nelements, true); 79 | }); 80 | 81 | hdfdb.def("getDoubleArray", []( 82 | HDFDatabaseMPIO &self, const std::string& key, int nelements, 83 | int offset, int block_size, int stride) 84 | { 85 | double *dataptr = new double[nelements]; 86 | self.getDoubleArray(key, dataptr, nelements, offset, block_size, stride); 87 | return get1DArrayFromPtr(dataptr, nelements, true); 88 | }); 89 | 90 | hdfdb.def("writeAttribute", &HDFDatabaseMPIO::writeAttribute); 91 | #endif 92 | } 93 | 94 | -------------------------------------------------------------------------------- /docker/baseline/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:22.04 2 | 3 | ENV ENVDIR=env 4 | 5 | # install sudo 6 | RUN apt-get -yq update && apt-get -yq install sudo 7 | 8 | WORKDIR /$ENVDIR 9 | 10 | # install packages 11 | RUN sudo apt-get install -yq git 12 | RUN sudo apt-get install --no-install-recommends -yq make gcc gfortran libssl-dev cmake 13 | RUN sudo apt-get install -yq libopenblas-dev libmpich-dev libblas-dev liblapack-dev libscalapack-mpi-dev libhdf5-mpi-dev hdf5-tools 14 | RUN sudo apt-get install -yq vim 15 | RUN sudo apt-get install -yq git-lfs 16 | RUN sudo apt-get install -yq valgrind 17 | RUN sudo apt-get install -yq wget 18 | RUN sudo apt-get install -yq astyle 19 | RUN sudo apt-get install -yq chrpath 20 | 21 | RUN sudo apt-get clean -q 22 | 23 | # download dependencies 24 | ENV LIB_DIR=/$ENVDIR/dependencies 25 | WORKDIR $LIB_DIR 26 | 27 | # install googletest 28 | WORKDIR $LIB_DIR 29 | RUN git clone https://github.com/google/googletest 30 | WORKDIR ./googletest 31 | # Last release that supports c++11 32 | RUN git checkout tags/release-1.12.1 -b v1.12.1 33 | WORKDIR ./build 34 | RUN cmake .. 35 | RUN make 36 | RUN sudo make install 37 | 38 | # install python 39 | RUN sudo apt-get update 40 | RUN sudo apt-get install -yq python3 41 | RUN sudo apt-get install -yq python3-dev 42 | RUN sudo apt-get install -yq python3-pip 43 | 44 | RUN echo "numpy" >> requirements.txt 45 | RUN echo "scipy" >> requirements.txt 46 | RUN echo "argparse" >> requirements.txt 47 | RUN echo "tables" >> requirements.txt 48 | RUN echo "PyYAML" >> requirements.txt 49 | RUN echo "h5py" >> requirements.txt 50 | RUN echo "pybind11" >> requirements.txt 51 | RUN echo "pytest" >> requirements.txt 52 | RUN echo "mpi4py" >> requirements.txt 53 | RUN sudo pip3 install --upgrade pip 54 | RUN sudo pip3 install -r ./requirements.txt 55 | 56 | # install pymfem 57 | RUN sudo pip3 install swig 58 | 59 | WORKDIR $LIB_DIR 60 | RUN git clone https://github.com/mfem/PyMFEM.git 61 | WORKDIR ./PyMFEM 62 | # --with-gslib flag does not work with later versions. 63 | RUN git checkout v_4.7.0.1 64 | # We need to use this hack until we can submit a pull request to PyMFEM. 65 | #RUN wget -O setup.py https://github.com/LLNL/pylibROM/raw/prom_parallel/extern/PyMFEM.setup.py 66 | RUN sudo python3 setup.py install --with-parallel --with-gslib --with-lapack 67 | 68 | # install lldb and gdb for debugging 69 | RUN sudo apt-get install -yq lldb gdb 70 | 71 | # create and switch to a user 72 | ENV USERNAME=test 73 | RUN echo "$USERNAME ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers 74 | RUN useradd --no-log-init -u 1001 --create-home --shell /bin/bash $USERNAME 75 | RUN adduser $USERNAME sudo 76 | USER $USERNAME 77 | WORKDIR /home/$USERNAME 78 | -------------------------------------------------------------------------------- /docker/jupyter/Dockerfile: -------------------------------------------------------------------------------- 1 | # start from pylibrom docker container 2 | FROM --platform=linux/amd64 ghcr.io/llnl/pylibrom/pylibrom_env:latest 3 | ENV ENVDIR=env 4 | ENV LIB_DIR=/$ENVDIR/dependencies 5 | WORKDIR $LIB_DIR 6 | 7 | # WORKDIR /env/dependencies 8 | RUN sudo git clone --recursive https://github.com/LLNL/pylibROM.git 9 | WORKDIR pylibROM 10 | RUN sudo -E pip install ./ --global-option="--librom_dir=/env/dependencies/libROM" 11 | 12 | # Install Jupyter Notebook 13 | RUN sudo apt-get install -yq python3-pip 14 | RUN sudo pip3 install jupyter 15 | 16 | # Create a directory for Jupyter notebooks 17 | RUN mkdir /home/$USERNAME/notebooks 18 | WORKDIR /home/$USERNAME/notebooks 19 | 20 | # Configure Jupyter Notebook 21 | RUN jupyter notebook --generate-config 22 | RUN echo "c.NotebookApp.ip = '*'" >> /home/$USERNAME/.jupyter/jupyter_notebook_config.py 23 | 24 | # Expose the Jupyter Notebook port 25 | EXPOSE 8888 26 | 27 | # Run Jupyter Notebook 28 | CMD ["jupyter", "notebook", "--ip=0.0.0.0", "--port=8888", "--no-browser", "--allow-root"] 29 | 30 | # create and switch to a user 31 | WORKDIR /home/$USERNAME 32 | -------------------------------------------------------------------------------- /docker/librom/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ghcr.io/llnl/librom/librom_env:latest 2 | 3 | RUN sudo apt-get -yq update 4 | RUN sudo apt-get install -yq chrpath 5 | 6 | # Add any more dependencies you would like to have in ci test/development environment. 7 | # RUN python3 -m pip install numpy 8 | RUN sudo pip3 install --upgrade pip 9 | RUN sudo pip3 install swig 10 | 11 | WORKDIR $LIB_DIR 12 | RUN sudo git clone https://github.com/mfem/PyMFEM.git 13 | WORKDIR ./PyMFEM 14 | # --with-gslib flag does not work with later versions. 15 | RUN sudo git checkout v_4.7.0.1 16 | # We need to use this hack until we can submit a pull request to PyMFEM. 17 | #RUN sudo wget -O setup.py https://github.com/LLNL/pylibROM/raw/prom_parallel/extern/PyMFEM.setup.py 18 | RUN sudo python3 setup.py install --with-parallel --with-gslib --with-lapack 19 | 20 | # install libROM 21 | WORKDIR $LIB_DIR 22 | RUN sudo git clone https://github.com/LLNL/libROM.git 23 | WORKDIR ./libROM 24 | RUN sudo git pull 25 | WORKDIR ./build 26 | RUN sudo cmake .. -DCMAKE_TOOLCHAIN_FILE=${TOOLCHAIN_FILE} -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DUSE_MFEM=${USE_MFEM} -DMFEM_USE_GSLIB=${MFEM_USE_GSLIB} 27 | # RUN sudo cmake .. -DCMAKE_TOOLCHAIN_FILE=${TOOLCHAIN_FILE} -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DUSE_MFEM=OFF 28 | RUN sudo make -j 16 29 | 30 | # ENV LIBROM_DIR=$LIB_DIR/libROM 31 | 32 | # create and switch to a user 33 | WORKDIR /home/$USERNAME 34 | -------------------------------------------------------------------------------- /examples/data/beam-hex-nurbs.mesh: -------------------------------------------------------------------------------- 1 | MFEM NURBS mesh v1.0 2 | 3 | # 4 | # MFEM Geometry Types (see mesh/geom.hpp): 5 | # 6 | # SEGMENT = 1 7 | # SQUARE = 3 8 | # CUBE = 5 9 | # 10 | 11 | dimension 12 | 3 13 | 14 | elements 15 | 2 16 | 1 5 0 1 4 5 6 7 10 11 17 | 2 5 1 2 3 4 7 8 9 10 18 | 19 | boundary 20 | 10 21 | 3 3 5 4 1 0 22 | 3 3 0 1 7 6 23 | 3 3 4 5 11 10 24 | 1 3 5 0 6 11 25 | 3 3 6 7 10 11 26 | 3 3 4 3 2 1 27 | 3 3 1 2 8 7 28 | 2 3 2 3 9 8 29 | 3 3 3 4 10 9 30 | 3 3 7 8 9 10 31 | 32 | edges 33 | 20 34 | 0 0 1 35 | 0 5 4 36 | 0 6 7 37 | 0 11 10 38 | 1 1 2 39 | 1 4 3 40 | 1 7 8 41 | 1 10 9 42 | 2 0 5 43 | 2 1 4 44 | 2 2 3 45 | 2 6 11 46 | 2 7 10 47 | 2 8 9 48 | 3 0 6 49 | 3 1 7 50 | 3 2 8 51 | 3 3 9 52 | 3 4 10 53 | 3 5 11 54 | 55 | vertices 56 | 12 57 | 58 | knotvectors 59 | 4 60 | 1 5 0 0 1 2 3 4 4 61 | 1 5 0 0 1 2 3 4 4 62 | 1 2 0 0 1 1 63 | 1 2 0 0 1 1 64 | 65 | weights 66 | 1 67 | 1 68 | 1 69 | 1 70 | 1 71 | 1 72 | 1 73 | 1 74 | 1 75 | 1 76 | 1 77 | 1 78 | 1 79 | 1 80 | 1 81 | 1 82 | 1 83 | 1 84 | 1 85 | 1 86 | 1 87 | 1 88 | 1 89 | 1 90 | 1 91 | 1 92 | 1 93 | 1 94 | 1 95 | 1 96 | 1 97 | 1 98 | 1 99 | 1 100 | 1 101 | 1 102 | 103 | FiniteElementSpace 104 | FiniteElementCollection: NURBS1 105 | VDim: 3 106 | Ordering: 1 107 | 108 | 0 0 0 109 | 4 0 0 110 | 8 0 0 111 | 8 1 0 112 | 4 1 0 113 | 0 1 0 114 | 0 0 1 115 | 4 0 1 116 | 8 0 1 117 | 8 1 1 118 | 4 1 1 119 | 0 1 1 120 | 1 0 0 121 | 2 0 0 122 | 3 0 0 123 | 3 1 0 124 | 2 1 0 125 | 1 1 0 126 | 1 0 1 127 | 2 0 1 128 | 3 0 1 129 | 3 1 1 130 | 2 1 1 131 | 1 1 1 132 | 5 0 0 133 | 6 0 0 134 | 7 0 0 135 | 7 1 0 136 | 6 1 0 137 | 5 1 0 138 | 5 0 1 139 | 6 0 1 140 | 7 0 1 141 | 7 1 1 142 | 6 1 1 143 | 5 1 1 144 | -------------------------------------------------------------------------------- /examples/data/beam-quad.mesh: -------------------------------------------------------------------------------- 1 | MFEM mesh v1.0 2 | 3 | # 4 | # MFEM Geometry Types (see mesh/geom.hpp): 5 | # 6 | # POINT = 0 7 | # SEGMENT = 1 8 | # TRIANGLE = 2 9 | # SQUARE = 3 10 | # TETRAHEDRON = 4 11 | # CUBE = 5 12 | # 13 | 14 | dimension 15 | 2 16 | 17 | elements 18 | 8 19 | 1 3 0 1 10 9 20 | 1 3 1 2 11 10 21 | 1 3 2 3 12 11 22 | 1 3 3 4 13 12 23 | 2 3 4 5 14 13 24 | 2 3 5 6 15 14 25 | 2 3 6 7 16 15 26 | 2 3 7 8 17 16 27 | 28 | boundary 29 | 18 30 | 3 1 0 1 31 | 3 1 1 2 32 | 3 1 2 3 33 | 3 1 3 4 34 | 3 1 4 5 35 | 3 1 5 6 36 | 3 1 6 7 37 | 3 1 7 8 38 | 3 1 10 9 39 | 3 1 11 10 40 | 3 1 12 11 41 | 3 1 13 12 42 | 3 1 14 13 43 | 3 1 15 14 44 | 3 1 16 15 45 | 3 1 17 16 46 | 1 1 9 0 47 | 2 1 8 17 48 | 49 | vertices 50 | 18 51 | 2 52 | 0 0 53 | 1 0 54 | 2 0 55 | 3 0 56 | 4 0 57 | 5 0 58 | 6 0 59 | 7 0 60 | 8 0 61 | 0 1 62 | 1 1 63 | 2 1 64 | 3 1 65 | 4 1 66 | 5 1 67 | 6 1 68 | 7 1 69 | 8 1 70 | -------------------------------------------------------------------------------- /examples/data/beam-tri.mesh: -------------------------------------------------------------------------------- 1 | MFEM mesh v1.0 2 | 3 | # 4 | # MFEM Geometry Types (see mesh/geom.hpp): 5 | # 6 | # POINT = 0 7 | # SEGMENT = 1 8 | # TRIANGLE = 2 9 | # SQUARE = 3 10 | # TETRAHEDRON = 4 11 | # CUBE = 5 12 | # 13 | 14 | dimension 15 | 2 16 | 17 | elements 18 | 16 19 | 1 2 10 0 1 20 | 1 2 0 10 9 21 | 1 2 11 1 2 22 | 1 2 1 11 10 23 | 1 2 12 2 3 24 | 1 2 2 12 11 25 | 1 2 13 3 4 26 | 1 2 3 13 12 27 | 2 2 14 4 5 28 | 2 2 4 14 13 29 | 2 2 15 5 6 30 | 2 2 5 15 14 31 | 2 2 16 6 7 32 | 2 2 6 16 15 33 | 2 2 17 7 8 34 | 2 2 7 17 16 35 | 36 | boundary 37 | 18 38 | 3 1 0 1 39 | 3 1 1 2 40 | 3 1 2 3 41 | 3 1 3 4 42 | 3 1 4 5 43 | 3 1 5 6 44 | 3 1 6 7 45 | 3 1 7 8 46 | 3 1 10 9 47 | 3 1 11 10 48 | 3 1 12 11 49 | 3 1 13 12 50 | 3 1 14 13 51 | 3 1 15 14 52 | 3 1 16 15 53 | 3 1 17 16 54 | 1 1 9 0 55 | 2 1 8 17 56 | 57 | vertices 58 | 18 59 | 2 60 | 0 0 61 | 1 0 62 | 2 0 63 | 3 0 64 | 4 0 65 | 5 0 66 | 6 0 67 | 7 0 68 | 8 0 69 | 0 1 70 | 1 1 71 | 2 1 72 | 3 1 73 | 4 1 74 | 5 1 75 | 6 1 76 | 7 1 77 | 8 1 78 | -------------------------------------------------------------------------------- /examples/data/inline-quad.mesh: -------------------------------------------------------------------------------- 1 | MFEM INLINE mesh v1.0 2 | 3 | type = quad 4 | nx = 4 5 | ny = 4 6 | sx = 1.0 7 | sy = 1.0 8 | -------------------------------------------------------------------------------- /examples/data/periodic-hexagon.mesh: -------------------------------------------------------------------------------- 1 | MFEM mesh v1.0 2 | 3 | # 4 | # MFEM Geometry Types (see mesh/geom.hpp): 5 | # 6 | # POINT = 0 7 | # SEGMENT = 1 8 | # TRIANGLE = 2 9 | # SQUARE = 3 10 | # TETRAHEDRON = 4 11 | # CUBE = 5 12 | # 13 | 14 | dimension 15 | 2 16 | 17 | # format: ... 18 | elements 19 | 12 20 | 21 | 1 3 0 2 8 5 22 | 1 3 2 1 3 8 23 | 1 3 5 8 6 11 24 | 1 3 8 3 0 6 25 | 26 | 2 3 0 4 9 6 27 | 2 3 4 1 2 9 28 | 2 3 6 9 7 11 29 | 2 3 9 2 0 7 30 | 31 | 3 3 0 3 10 7 32 | 3 3 3 1 4 10 33 | 3 3 7 10 5 11 34 | 3 3 10 4 0 5 35 | 36 | boundary 37 | 0 38 | 39 | vertices 40 | 12 41 | 42 | nodes 43 | FiniteElementSpace 44 | FiniteElementCollection: L2_T1_2D_P1 45 | VDim: 2 46 | Ordering: 1 47 | 48 | -0.50 -0.8660254037844386 49 | 0.00 -0.8660254037844386 50 | -0.25 -0.4330127018922193 51 | 0.25 -0.4330127018922193 52 | 53 | 0.00 -0.8660254037844386 54 | 0.50 -0.8660254037844386 55 | 0.25 -0.4330127018922193 56 | 0.75 -0.4330127018922193 57 | 58 | -0.25 -0.4330127018922193 59 | 0.25 -0.4330127018922193 60 | 0.00 0.0 61 | 0.50 0.0 62 | 63 | 0.25 -0.4330127018922193 64 | 0.75 -0.4330127018922193 65 | 0.50 0.0 66 | 1.00 0.0 67 | 68 | 1.00 0.0 69 | 0.75 0.4330127018922193 70 | 0.50 0.0 71 | 0.25 0.4330127018922193 72 | 73 | 0.75 0.4330127018922193 74 | 0.50 0.8660254037844386 75 | 0.25 0.4330127018922193 76 | 0.00 0.8660254037844386 77 | 78 | 0.50 0.0 79 | 0.25 0.4330127018922193 80 | 0.00 0.0 81 | -0.25 0.4330127018922193 82 | 83 | 0.25 0.4330127018922193 84 | 0.00 0.8660254037844386 85 | -0.25 0.4330127018922193 86 | -0.50 0.8660254037844386 87 | 88 | -0.50 0.8660254037844386 89 | -0.75 0.4330127018922193 90 | -0.25 0.4330127018922193 91 | -0.50 0.0 92 | 93 | -0.75 0.4330127018922193 94 | -1.00 0.0 95 | -0.50 0.0 96 | -0.75 -0.4330127018922193 97 | 98 | -0.25 0.4330127018922193 99 | -0.50 0.0 100 | 0.00 0.0 101 | -0.25 -0.4330127018922193 102 | 103 | -0.50 0.0 104 | -0.75 -0.4330127018922193 105 | -0.25 -0.4330127018922193 106 | -0.50 -0.8660254037844386 107 | -------------------------------------------------------------------------------- /examples/data/periodic-square.mesh: -------------------------------------------------------------------------------- 1 | MFEM mesh v1.0 2 | 3 | # 4 | # MFEM Geometry Types (see mesh/geom.hpp): 5 | # 6 | # POINT = 0 7 | # SEGMENT = 1 8 | # TRIANGLE = 2 9 | # SQUARE = 3 10 | # TETRAHEDRON = 4 11 | # CUBE = 5 12 | # 13 | 14 | dimension 15 | 2 16 | 17 | # format: ... 18 | elements 19 | 9 20 | 1 3 0 1 4 3 21 | 2 3 1 2 5 4 22 | 3 3 2 0 3 5 23 | 4 3 3 4 7 6 24 | 5 3 4 5 8 7 25 | 6 3 5 3 6 8 26 | 7 3 6 7 1 0 27 | 8 3 7 8 2 1 28 | 9 3 8 6 0 2 29 | 30 | boundary 31 | 0 32 | 33 | vertices 34 | 9 35 | 36 | nodes 37 | FiniteElementSpace 38 | FiniteElementCollection: L2_T1_2D_P1 39 | VDim: 2 40 | Ordering: 1 41 | 42 | -1 -1 43 | -0.333333333 -1 44 | -1 -0.333333333 45 | -0.333333333 -0.333333333 46 | 47 | -0.333333333 -1 48 | +0.333333333 -1 49 | -0.333333333 -0.333333333 50 | +0.333333333 -0.333333333 51 | 52 | +0.333333333 -1 53 | +1 -1 54 | +0.333333333 -0.333333333 55 | +1 -0.333333333 56 | 57 | -1 -0.333333333 58 | -0.333333333 -0.333333333 59 | -1 +0.333333333 60 | -0.333333333 +0.333333333 61 | 62 | -0.333333333 -0.333333333 63 | +0.333333333 -0.333333333 64 | -0.333333333 +0.333333333 65 | +0.333333333 +0.333333333 66 | 67 | +0.333333333 -0.333333333 68 | +1 -0.333333333 69 | +0.333333333 +0.333333333 70 | +1 +0.333333333 71 | 72 | -1 +0.333333333 73 | -0.333333333 +0.333333333 74 | -1 +1 75 | -0.333333333 +1 76 | 77 | -0.333333333 +0.333333333 78 | +0.333333333 +0.333333333 79 | -0.333333333 +1 80 | +0.333333333 +1 81 | 82 | +0.333333333 +0.333333333 83 | +1 +0.333333333 84 | +0.333333333 +1 85 | +1 +1 86 | -------------------------------------------------------------------------------- /examples/data/star.mesh: -------------------------------------------------------------------------------- 1 | MFEM mesh v1.0 2 | 3 | # 4 | # MFEM Geometry Types (see mesh/geom.hpp): 5 | # 6 | # POINT = 0 7 | # SEGMENT = 1 8 | # TRIANGLE = 2 9 | # SQUARE = 3 10 | # TETRAHEDRON = 4 11 | # CUBE = 5 12 | # 13 | 14 | dimension 15 | 2 16 | 17 | elements 18 | 20 19 | 1 3 0 11 26 14 20 | 1 3 0 14 27 17 21 | 1 3 0 17 28 20 22 | 1 3 0 20 29 23 23 | 1 3 0 23 30 11 24 | 1 3 11 1 12 26 25 | 1 3 26 12 3 13 26 | 1 3 14 26 13 2 27 | 1 3 14 2 15 27 28 | 1 3 27 15 5 16 29 | 1 3 17 27 16 4 30 | 1 3 17 4 18 28 31 | 1 3 28 18 7 19 32 | 1 3 20 28 19 6 33 | 1 3 20 6 21 29 34 | 1 3 29 21 9 22 35 | 1 3 23 29 22 8 36 | 1 3 23 8 24 30 37 | 1 3 30 24 10 25 38 | 1 3 11 30 25 1 39 | 40 | boundary 41 | 20 42 | 1 1 13 2 43 | 1 1 12 3 44 | 1 1 16 4 45 | 1 1 15 5 46 | 1 1 19 6 47 | 1 1 18 7 48 | 1 1 22 8 49 | 1 1 21 9 50 | 1 1 25 1 51 | 1 1 24 10 52 | 1 1 3 13 53 | 1 1 1 12 54 | 1 1 5 16 55 | 1 1 2 15 56 | 1 1 7 19 57 | 1 1 4 18 58 | 1 1 9 22 59 | 1 1 6 21 60 | 1 1 10 25 61 | 1 1 8 24 62 | 63 | vertices 64 | 31 65 | 2 66 | 0 0 67 | 1 0 68 | 0.309017 0.951057 69 | 1.30902 0.951057 70 | -0.809017 0.587785 71 | -0.5 1.53884 72 | -0.809017 -0.587785 73 | -1.61803 0 74 | 0.309017 -0.951057 75 | -0.5 -1.53884 76 | 1.30902 -0.951057 77 | 0.5 0 78 | 1.15451 0.475529 79 | 0.809019 0.951057 80 | 0.154508 0.475529 81 | -0.0954915 1.24495 82 | -0.654508 1.06331 83 | -0.404508 0.293893 84 | -1.21352 0.293893 85 | -1.21352 -0.293892 86 | -0.404508 -0.293893 87 | -0.654508 -1.06331 88 | -0.0954915 -1.24495 89 | 0.154508 -0.475529 90 | 0.809019 -0.951057 91 | 1.15451 -0.475529 92 | 0.654509 0.475529 93 | -0.25 0.769421 94 | -0.809016 0 95 | -0.25 -0.76942 96 | 0.654509 -0.475529 97 | -------------------------------------------------------------------------------- /examples/dmd/heat_conduction_csv.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #SBATCH -N 1 4 | #SBATCH -t 0:05:00 5 | #SBATCH -p pdebug 6 | #SBATCH -o sbatch.log 7 | #SBATCH --open-mode truncate 8 | 9 | rm -rf parameters.txt dmd_list dmd_data run/dmd_data 10 | 11 | python3 ./parametric_heat_conduction.py -r 0.40 -save -csv -out dmd_data/dmd_par1 -no-vis > hc_par1.log 12 | python3 ./parametric_heat_conduction.py -r 0.45 -save -csv -out dmd_data/dmd_par2 -no-vis > hc_par2.log 13 | python3 ./parametric_heat_conduction.py -r 0.55 -save -csv -out dmd_data/dmd_par3 -no-vis > hc_par3.log 14 | python3 ./parametric_heat_conduction.py -r 0.60 -save -csv -out dmd_data/dmd_par4 -no-vis > hc_par4.log 15 | python3 ./parametric_heat_conduction.py -r 0.50 -save -csv -out dmd_data/dmd_par5 -no-vis > hc_par5.log 16 | 17 | mkdir dmd_list 18 | mv -f run/dmd_data . 19 | 20 | awk 'END{print NR}' dmd_data/dmd_par1/step0/sol.csv > dmd_data/dim.csv 21 | 22 | mv dmd_data/dmd_par1/snap_list.csv dmd_list/dmd_par1.csv 23 | mv dmd_data/dmd_par2/snap_list.csv dmd_list/dmd_par2.csv 24 | mv dmd_data/dmd_par3/snap_list.csv dmd_list/dmd_par3.csv 25 | mv dmd_data/dmd_par4/snap_list.csv dmd_list/dmd_par4.csv 26 | mv dmd_data/dmd_par5/snap_list.csv dmd_list/dmd_par5.csv 27 | 28 | echo "dmd_par1,0.40,0.01,0,0" > dmd_list/dmd_train_parametric.csv 29 | echo "dmd_par2,0.45,0.01,0,0" >> dmd_list/dmd_train_parametric.csv 30 | echo "dmd_par3,0.55,0.01,0,0" >> dmd_list/dmd_train_parametric.csv 31 | echo "dmd_par4,0.60,0.01,0,0" >> dmd_list/dmd_train_parametric.csv 32 | echo "dmd_par5,0.50,0.01,0,0" > dmd_list/dmd_train_local.csv 33 | echo "dmd_par5,0.50,0.01,0,0" > dmd_list/dmd_test.csv 34 | -------------------------------------------------------------------------------- /examples/dmd/heat_conduction_hdf.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #SBATCH -N 1 4 | #SBATCH -t 0:05:00 5 | #SBATCH -p pdebug 6 | #SBATCH -o sbatch.log 7 | #SBATCH --open-mode truncate 8 | 9 | rm -rf parameters.txt dmd_list dmd_data run/dmd_data 10 | 11 | python3 ./parametric_heat_conduction.py -r 0.40 -save -hdf -out dmd_data/sim0 -no-vis > hc_par0.log 12 | python3 ./parametric_heat_conduction.py -r 0.45 -save -hdf -out dmd_data/sim1 -no-vis > hc_par1.log 13 | python3 ./parametric_heat_conduction.py -r 0.55 -save -hdf -out dmd_data/sim2 -no-vis > hc_par2.log 14 | python3 ./parametric_heat_conduction.py -r 0.60 -save -hdf -out dmd_data/sim3 -no-vis > hc_par3.log 15 | python3 ./parametric_heat_conduction.py -r 0.50 -save -hdf -out dmd_data/sim4 -no-vis > hc_par4.log 16 | 17 | mkdir dmd_list 18 | mv -f run/dmd_data . 19 | 20 | echo "0,0.40,0.01,0,0" > dmd_list/dmd_train_parametric.csv 21 | echo "1,0.45,0.01,0,0" >> dmd_list/dmd_train_parametric.csv 22 | echo "2,0.55,0.01,0,0" >> dmd_list/dmd_train_parametric.csv 23 | echo "3,0.60,0.01,0,0" >> dmd_list/dmd_train_parametric.csv 24 | echo "4,0.50,0.01,0,0" > dmd_list/dmd_train_local.csv 25 | echo "4,0.50,0.01,0,0" > dmd_list/dmd_test.csv 26 | -------------------------------------------------------------------------------- /extern/librom_scalapack.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | check_result () { 3 | # $1: Result output of the previous command ($?) 4 | # $2: Name of the previous command 5 | if [ $1 -eq 0 ]; then 6 | echo "$2 succeeded" 7 | else 8 | echo "$2 failed" 9 | exit -1 10 | fi 11 | } 12 | 13 | SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )" 14 | LIB_DIR=$SCRIPT_DIR/libROM/dependencies 15 | mkdir -p $LIB_DIR 16 | 17 | # Install ScaLAPACK if specified. 18 | cd $LIB_DIR 19 | if [ -f "scalapack-2.2.0/libscalapack.a" ]; then 20 | echo "Using dependencies/scalapack-2.2.0/libscalapack.a" 21 | else 22 | echo "ScaLAPACK is needed!" 23 | tar -zxvf scalapack-2.2.0.tar.gz 24 | cp SLmake.inc scalapack-2.2.0/ 25 | cd scalapack-2.2.0/ 26 | make 27 | check_result $? ScaLAPACK-installation 28 | fi 29 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["setuptools==70.1.0", "mpi4py"] 3 | build-backend = "setuptools.build_meta" 4 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import os 2 | import re 3 | import subprocess 4 | import sys 5 | from pathlib import Path 6 | 7 | # NOTE: Current setup.py uses "--global-option", which is deprecated and will not be available from pip 23.3. 8 | # It recommends using "--config-settings", though there is no clear documentation about this. 9 | # For now, we enforce to use the versions < 23.3.0. 10 | import pkg_resources 11 | #pkg_resources.require(['pip < 23.3.0']) 12 | 13 | from setuptools import Extension, setup, find_packages 14 | from setuptools.command.build_ext import build_ext 15 | from setuptools.command.install import install as _install 16 | 17 | # Take the global option for pre-installed librom directory. 18 | librom_dir = None 19 | install_scalapack = False 20 | use_mfem = True 21 | # TODO: fix this.. passing options through pip to setuptools with PEP517 is not working 22 | for arg in sys.argv: 23 | if (arg[:13] == "--librom_dir=" or arg[:13] == "--librom-dir="): 24 | librom_dir = arg[13:] 25 | if (arg[:19] == "--install_scalapack"): 26 | install_scalapack = True 27 | if (arg[:9] == "--no-mfem"): 28 | use_mfem = False 29 | if (arg[:10] == "--use-mfem"): 30 | use_mfem = True 31 | 32 | # Convert distutils Windows platform specifiers to CMake -A arguments 33 | PLAT_TO_CMAKE = { 34 | "win32": "Win32", 35 | "win-amd64": "x64", 36 | "win-arm32": "ARM", 37 | "win-arm64": "ARM64", 38 | } 39 | 40 | # A CMakeExtension needs a sourcedir instead of a file list. 41 | # The name must be the _single_ output extension from the CMake build. 42 | # If you need multiple extensions, see scikit-build. 43 | class CMakeExtension(Extension): 44 | def __init__(self, name: str, sourcedir: str = "") -> None: 45 | super().__init__(name, sources=[]) 46 | self.sourcedir = os.fspath(Path(sourcedir).resolve()) 47 | 48 | 49 | class InstallBuild(_install): 50 | 51 | user_options = _install.user_options + [ 52 | ("librom-dir=", None, "Path to libROM root directory. If specified, pylibROM will use this instead of compiling its own libROM."), 53 | ("install-scalapack", None, "Enables SCALAPACK when building libROM."), 54 | ("use-mfem", None, "Compile pylibROM with MFEM enabled."), 55 | ("no-mfem", None, "Compile pylibROM without MFEM.") 56 | ] 57 | 58 | negative_opt = dict(_install.negative_opt) 59 | negative_opt.update({"no-mfem" : "use-mfem"}) 60 | 61 | def run(self): 62 | _install.run(self) 63 | 64 | 65 | def initialize_options(self): 66 | _install.initialize_options(self) 67 | self.librom_dir = None 68 | self.install_scalapack = False 69 | self.use_mfem = True 70 | 71 | 72 | def finalize_options(self): 73 | global librom_dir, install_scalapack, use_mfem 74 | librom_dir = self.librom_dir 75 | install_scalapack = self.install_scalapack 76 | use_mfem = self.use_mfem 77 | 78 | _install.finalize_options(self) 79 | 80 | 81 | class CMakeBuild(build_ext): 82 | def build_extension(self, ext: CMakeExtension) -> None: 83 | # Must be in this form due to bug in .resolve() only fixed in Python 3.10+ 84 | ext_fullpath = Path.cwd() / self.get_ext_fullpath(ext.name) 85 | extdir = ext_fullpath.parent.resolve() 86 | 87 | # Using this requires trailing slash for auto-detection & inclusion of 88 | # auxiliary "native" libs 89 | 90 | debug = int(os.environ.get("DEBUG", 0)) if self.debug is None else self.debug 91 | cfg = "Debug" if debug else "Release" 92 | 93 | # CMake lets you override the generator - we need to check this. 94 | # Can be set with Conda-Build, for example. 95 | cmake_generator = os.environ.get("CMAKE_GENERATOR", "") 96 | 97 | global librom_dir, install_scalapack, use_mfem 98 | cmake_args = [] 99 | if (librom_dir is None): 100 | librom_dir = os.path.dirname(os.path.realpath(__file__)) 101 | librom_dir += "/extern/libROM/" 102 | print("Installing libROM library: %s" % librom_dir) 103 | 104 | librom_cmd = "cd %s && ./scripts/compile.sh -t ./cmake/toolchains/simple.cmake" % librom_dir 105 | if (install_scalapack): librom_cmd += " -s" 106 | if (use_mfem): librom_cmd += " -m -g -l" 107 | print("libROM installation command: %s" % librom_cmd) 108 | subprocess.run( 109 | librom_cmd, shell=True, check=True 110 | ) 111 | else: 112 | print("Using pre-installed libROM library: %s" % librom_dir) 113 | cmake_args += [f"-DLIBROM_DIR=%s" % librom_dir] 114 | 115 | cmake_args += ["-DUSE_MFEM={:s}".format('ON' if use_mfem else 'OFF')] 116 | 117 | # Set Python_EXECUTABLE instead if you use PYBIND11_FINDPYTHON 118 | # EXAMPLE_VERSION_INFO shows you how to pass a value into the C++ code 119 | # from Python. 120 | cmake_args += [ 121 | f"-DCMAKE_LIBRARY_OUTPUT_DIRECTORY={extdir}{os.sep}", 122 | f"-DPYTHON_EXECUTABLE={sys.executable}", 123 | f"-DCMAKE_BUILD_TYPE={cfg}", # not used on MSVC, but no harm 124 | ] 125 | build_args = [] 126 | # Adding CMake arguments set as environment variable 127 | # (needed e.g. to build for ARM OSx on conda-forge) 128 | if "CMAKE_ARGS" in os.environ: 129 | cmake_args += [item for item in os.environ["CMAKE_ARGS"].split(" ") if item] 130 | 131 | # In this example, we pass in the version to C++. You might not need to. 132 | cmake_args += [f"-DEXAMPLE_VERSION_INFO={self.distribution.get_version()}"] 133 | 134 | if self.compiler.compiler_type != "msvc": 135 | # Using Ninja-build since it a) is available as a wheel and b) 136 | # multithreads automatically. MSVC would require all variables be 137 | # exported for Ninja to pick it up, which is a little tricky to do. 138 | # Users can override the generator with CMAKE_GENERATOR in CMake 139 | # 3.15+. 140 | if not cmake_generator or cmake_generator == "Ninja": 141 | try: 142 | import ninja 143 | 144 | ninja_executable_path = Path(ninja.BIN_DIR) / "ninja" 145 | cmake_args += [ 146 | "-GNinja", 147 | f"-DCMAKE_MAKE_PROGRAM:FILEPATH={ninja_executable_path}", 148 | ] 149 | except ImportError: 150 | pass 151 | 152 | else: 153 | # Single config generators are handled "normally" 154 | single_config = any(x in cmake_generator for x in {"NMake", "Ninja"}) 155 | 156 | # CMake allows an arch-in-generator style for backward compatibility 157 | contains_arch = any(x in cmake_generator for x in {"ARM", "Win64"}) 158 | 159 | # Specify the arch if using MSVC generator, but only if it doesn't 160 | # contain a backward-compatibility arch spec already in the 161 | # generator name. 162 | if not single_config and not contains_arch: 163 | cmake_args += ["-A", PLAT_TO_CMAKE[self.plat_name]] 164 | 165 | # Multi-config generators have a different way to specify configs 166 | if not single_config: 167 | cmake_args += [ 168 | f"-DCMAKE_LIBRARY_OUTPUT_DIRECTORY_{cfg.upper()}={extdir}" 169 | ] 170 | build_args += ["--config", cfg] 171 | 172 | if sys.platform.startswith("darwin"): 173 | # Cross-compile support for macOS - respect ARCHFLAGS if set 174 | archs = re.findall(r"-arch (\S+)", os.environ.get("ARCHFLAGS", "")) 175 | if archs: 176 | cmake_args += ["-DCMAKE_OSX_ARCHITECTURES={}".format(";".join(archs))] 177 | 178 | # Set CMAKE_BUILD_PARALLEL_LEVEL to control the parallel build level 179 | # across all generators. 180 | if "CMAKE_BUILD_PARALLEL_LEVEL" not in os.environ: 181 | # self.parallel is a Python 3 only way to set parallel jobs by hand 182 | # using -j in the build_ext call, not supported by pip or PyPA-build. 183 | if hasattr(self, "parallel") and self.parallel: 184 | # CMake 3.12+ only. 185 | build_args += [f"-j{self.parallel}"] 186 | 187 | build_temp = Path(self.build_temp) / ext.name 188 | if not build_temp.exists(): 189 | build_temp.mkdir(parents=True) 190 | 191 | subprocess.run( 192 | ["cmake", ext.sourcedir, *cmake_args], cwd=build_temp, check=True 193 | ) 194 | subprocess.run( 195 | ["cmake", "--build", ".", "-j 8", "-v", *build_args], cwd=build_temp, check=True 196 | ) 197 | 198 | 199 | def initialize_options(self): 200 | build_ext.initialize_options(self) 201 | 202 | 203 | def finalize_options(self): 204 | build_ext.finalize_options(self) 205 | 206 | 207 | # The information here can also be placed in setup.cfg - better separation of 208 | # logic and declaration, and simpler if you include description/version in a file. 209 | setup( 210 | name="pylibROM", 211 | description="Python Interface for LLNL libROM", 212 | long_description="", 213 | packages=find_packages(where='bindings', exclude=['pylibROM.mfem'] if use_mfem == False else ['']), 214 | package_dir={"":"bindings"}, 215 | ext_modules=[CMakeExtension("_pylibROM")], 216 | cmdclass={ 217 | "build_ext": CMakeBuild, 218 | "install": InstallBuild 219 | }, 220 | zip_safe=False, 221 | extras_require={"test": ["pytest>=6.0"]}, 222 | python_requires=">=3.7", 223 | ) 224 | -------------------------------------------------------------------------------- /tests/test_Options.py: -------------------------------------------------------------------------------- 1 | # import sys 2 | # sys.path.append("..") 3 | 4 | import pylibROM.linalg as libROM 5 | import numpy as np 6 | 7 | #Testing with two arguments 8 | options = libROM.Options(4, 20) 9 | print("dim",options.dim) 10 | print("max_basis_dimension",options.max_basis_dimension) 11 | print("max_num_samples",options.max_num_samples) 12 | print("update_right_SV",options.update_right_SV) 13 | print("write_snapshots",options.write_snapshots) 14 | 15 | #Testing with all arguments 16 | options = libROM.Options(4, 20,True,False) 17 | print("dim",options.dim) 18 | print("max_num_samples",options.max_num_samples) 19 | print("update_right_SV",options.update_right_SV) 20 | print("write_snapshots",options.write_snapshots) 21 | 22 | # Test the member functions 23 | print("set max_basis_dimension value to 10 using setMaxBasisDimension",options.setMaxBasisDimension(10).max_basis_dimension) 24 | print("set singular_value_tol value to 0.01 using setSingularValueTol",options.setSingularValueTol(0.01).singular_value_tol) 25 | print("set debug_algorithm to true using setDebugMode",options.setDebugMode(True).debug_algorithm) 26 | options.setRandomizedSVD(True, randomized_subspace_dim_=5, random_seed_=42) 27 | options.setIncrementalSVD(linearity_tol_=0.001, initial_dt_=0.1, sampling_tol_=0.001, max_time_between_samples_=1.0, fast_update_=True, skip_linearly_dependent_=False) 28 | options.setStateIO(save_state_=True, restore_state_=False) 29 | options.setSamplingTimeStepScale(min_sampling_time_step_scale_=0.5, sampling_time_step_scale_=1.0, max_sampling_time_step_scale_=2.0) 30 | 31 | 32 | print("set randomized to true using setRandomizedSVD",options.randomized) 33 | print("set randomized_subspace_dim to 5 using setRandomizedSVD",options.randomized_subspace_dim) 34 | print("set random_seed value to 42 using setRandomizedSVD",options.random_seed) 35 | print("set linearity_tol value to 0.001 using setIncrementalSVD",options.linearity_tol) 36 | print("set initial_dt value to 0.1 using setIncrementalSVD",options.initial_dt) 37 | print("set sampling_tol value to 0.001 using setIncrementalSVD",options.sampling_tol) 38 | print("set max_time_between_samples value to 1.0 using setIncrementalSVD",options.max_time_between_samples) 39 | print("set fast_update value to true using setIncrementalSVD",options.fast_update) 40 | print("set skip_linearly_dependent value to false using setIncrementalSVD",options.skip_linearly_dependent) 41 | print("set save_state value to true using setStateIO",options.save_state) 42 | print("set restore_state value to false using setStateIO",options.restore_state) 43 | print("set min_sampling_time_step_scale value to 0.5 using setSamplingTimeStepScale",options.min_sampling_time_step_scale) 44 | print("set sampling_time_step_scale value to 1.0 using setSamplingTimeStepScale",options.sampling_time_step_scale) 45 | print("set max_sampling_time_step_scale value to 2.0 using setSamplingTimeStepScale",options.max_sampling_time_step_scale) -------------------------------------------------------------------------------- /tests/test_Vector.py: -------------------------------------------------------------------------------- 1 | import sys 2 | sys.path.append("../build") 3 | 4 | import pylibROM.linalg as libROM 5 | 6 | 7 | # Create two Vector objects 8 | v1 = libROM.Vector(3, False) 9 | v2 = libROM.Vector(3, False) 10 | 11 | # Set the values for v1 and v2 12 | v1.fill(1.0) 13 | v2.fill(2.0) 14 | 15 | # Print the initial data for v1 and v2 16 | print("Initial data for v1:", v1.get_data()) 17 | print("Initial data for v2:", v2.get_data()) 18 | 19 | # Test copy constructor 20 | v3 = libROM.Vector(v1) 21 | print("Create a new Vector(v3) using the copy constructor: ",v3.get_data()) 22 | 23 | # Test assignment operator 24 | v3 = v2 25 | print("Assign v2 to v3 using the assignment operator: ",v3.get_data()) 26 | 27 | # Use the addition operator 28 | v1 += v2 29 | 30 | # Print the updated data for v1 31 | print("Updated data for v1 after addition:", v1.get_data()) 32 | 33 | # Subtract v2 from v1 using the -= operator 34 | v1 -= v2 35 | print("Updated data for v1 after subtraction:", v1.get_data()) 36 | 37 | #set every element to a scalar 38 | v1.__set_scalar__(2) 39 | 40 | # Print the updated data for v1 41 | print("Updated data for v1 after setting every element to a scalar:", v1.get_data()) 42 | 43 | #scaling every element by a scalar 44 | v1.__scale__(3) 45 | 46 | # Print the updated data for v1 47 | print("Updated data for v1 after scaling every element by a scalar:", v1.get_data()) 48 | 49 | #set size 50 | v1.setSize(5) 51 | v1.__set_scalar__(2) 52 | 53 | # Print the updated data for v1 54 | print("Updated data for v1 after setting the size:", v1.get_data()) 55 | 56 | #tranformers 57 | # Define the transformer function 58 | def transformer(size, vector): 59 | for i in range(size): 60 | vector[i] = vector[i] ** 2 61 | v1.transform(transformer) 62 | print("Updated data for v1 after tranforming:", v1.get_data()) 63 | 64 | 65 | print("distributed:", v1.distributed()) 66 | 67 | print("v1 dim:", v1.dim()) 68 | 69 | #inner product 70 | v2.setSize(5) 71 | v2.__set_scalar__(3) 72 | print("inner product of v1 &v2", v1.inner_product(v2)) 73 | 74 | # Call the norm function 75 | norm = v1.norm() 76 | print("Norm:", norm) 77 | 78 | # Call the norm2 function 79 | norm2 = v1.norm2() 80 | print("Norm squared:", norm2) 81 | 82 | # Call the normalize function 83 | v1.normalize() 84 | normalized_data = v1.get_data() 85 | print("Normalized data:", normalized_data) 86 | 87 | #add two vectors 88 | #Test the first version of plus 89 | result=v1.plus(v2) 90 | print("Result vector after addition of v1 and v2 ", result.get_data()) 91 | 92 | # Test the third version of plus 93 | v1.plus(v2,v1) 94 | print("Updated data for v1 after addition of v1 and v2 ", v1.get_data()) 95 | 96 | 97 | # Test plusAx function that returns a new Vector 98 | result1 = v1.plusAx(2.0, v2) 99 | print("Result vector of plusAx function", result1.get_data()) 100 | 101 | # Test plusAx function that modifies an existing Vector 102 | result2 = libROM.Vector() 103 | v1.plusAx(2.0, v2, result2) 104 | print("Result vector(existing vector) of plusAx function", result2.get_data()) 105 | 106 | 107 | #Test the first version of plusEqAx 108 | v1.plusEqAx(2.0, v2) 109 | print("Updated data for v1 after plusEqAx", v1.get_data()) 110 | 111 | #Test the first version of minus 112 | result=v1.minus(v2) 113 | print("Result vector after subtraction of v1 and v2 ", result.get_data()) 114 | 115 | # Test the third version of minus 116 | v1.minus(v2,v1) 117 | print("Updated data for v1 after subtraction of v1 and v2 ", v1.get_data()) 118 | 119 | 120 | # Test mult function that returns a new Vector 121 | result1 = v1.mult(2.0) 122 | print("The result vector of multiplication of vector v1 by a factor of 2.0",result1.get_data()) 123 | 124 | # Test mult function that modifies an existing Vector 125 | result2 = libROM.Vector() 126 | v1.mult(2.0, result2) 127 | print("The result vector(existing vector) of multiplication of vector v1 by a factor of 2.0",result2.get_data()) 128 | 129 | v1=libROM.Vector(2,False) 130 | v1.__setitem__(0, 0) 131 | v1.__setitem__(1, 2.0) 132 | print("Set Item(1) of vector v1 to 2.0 ",v1.get_data()) 133 | print("Get Item (1) of vector v1",v1.__getitem__(1) ) 134 | value= v1(1) 135 | print("value",value) 136 | print("call function",v1.__call__(1)) 137 | 138 | # Test the 'localMin' function 139 | local_min = v1.localMin(0) 140 | 141 | # Print the local minimum value 142 | print("Local Minimum of v1:", local_min) 143 | 144 | 145 | v2=libROM.Vector(2,False) 146 | v2.fill(4.0) 147 | pointers = [v1, v2] 148 | 149 | # Test getCenterPoint with vector of Vector pointers 150 | center_point_1 = libROM.getCenterPoint(pointers, True) 151 | print("GetCenterPoint with vector of Vector pointers(v1,v2)",center_point_1) 152 | 153 | # Create a vector of Vector objects 154 | objects = [v1, v2] 155 | 156 | # Test getCenterPoint with vector of Vector objects 157 | center_point_2 = libROM.getCenterPoint(objects, True) 158 | print("GetCenterPoint with vector of Vector objects",center_point_2) 159 | 160 | # Create a test Vector object 161 | test_point = libROM.Vector(2,False) 162 | test_point.fill(3.0) 163 | 164 | # Test getClosestPoint with vector of Vector pointers 165 | closest_point_1 = libROM.getClosestPoint(pointers, test_point) 166 | print("GetClosestPoint with vector of Vector pointers",closest_point_1) 167 | 168 | # Test getClosestPoint with vector of Vector objects 169 | closest_point_2 = libROM.getClosestPoint(objects, test_point) 170 | print("GetClosestPoint with vector of Vector objects",closest_point_2) -------------------------------------------------------------------------------- /tests/test_pyBasisGenerator.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import pytest 3 | try: 4 | # import pip-installed package 5 | import pylibROM 6 | import pylibROM.linalg as libROM 7 | from pylibROM.utils import Database 8 | except ModuleNotFoundError: 9 | # If pip-installed package is not found, import cmake-built package 10 | sys.path.append("../build") 11 | import _pylibROM as pylibROM 12 | import _pylibROM.linalg as libROM 13 | from _pylibROM.utils import Database 14 | import numpy as np 15 | import h5py 16 | 17 | 18 | def test_isNextSample(): 19 | options = libROM.Options(4, 20, True, True) 20 | incremental = False 21 | basis_file_name = "basis.h5" 22 | file_format = Database.formats.HDF5 23 | generator = libROM.BasisGenerator(options, incremental, basis_file_name, file_format) 24 | time = 1.0 25 | is_next = generator.isNextSample(time) 26 | assert is_next 27 | 28 | def test_updateRightSV(): 29 | options = libROM.Options(4, 20, True, True) 30 | generator = libROM.BasisGenerator(options, False, "basis.h5", Database.formats.HDF5) 31 | update_success = generator.updateRightSV() 32 | assert update_success 33 | 34 | def test_takeSample(): 35 | options = libROM.Options(4, 20, True, True) 36 | generator = libROM.BasisGenerator(options, False, "basis.h5", Database.formats.HDF5) 37 | u_in_data = np.array([1.0, 2.0, 3.0]) 38 | result = generator.takeSample(u_in_data) 39 | assert result 40 | 41 | def test_writeSnapshot(): 42 | options = libROM.Options(4, 20, True, True) 43 | generator = libROM.BasisGenerator(options, False, "basis.h5", Database.formats.HDF5) 44 | generator.takeSample(np.array([1.0, 2.0, 3.0])) 45 | generator.writeSnapshot() 46 | 47 | def test_computeNextSampleTime(): 48 | options = libROM.Options(4, 20, True, True) 49 | generator1 = libROM.BasisGenerator(options, False, "basis.h5", Database.formats.HDF5) 50 | generator1.takeSample(np.array([1.0, 2.0, 3.0])) 51 | base_file_name = "test_basisgenerator_file" 52 | basis_writer = libROM.BasisWriter(generator1, base_file_name, Database.formats.HDF5) 53 | basis_writer.writeBasis("basis") 54 | del basis_writer 55 | del generator1 56 | generator = libROM.BasisGenerator(options, False, "basis.h5", Database.formats.HDF5) 57 | kind = "basis" 58 | cut_off = 10 59 | db_format = Database.formats.HDF5 60 | generator.loadSamples(base_file_name, kind, cut_off, db_format) 61 | u_in = [1.0, 2.0, 3.0] 62 | rhs_in = [0.1, 0.2, 0.3] 63 | time = 0.0 64 | next_sample_time = generator.computeNextSampleTime(u_in, rhs_in, time) 65 | assert next_sample_time == 0.0 66 | generator.endSamples() 67 | 68 | def test_getSpatialBasis(): 69 | options = libROM.Options(4, 20, True, True) 70 | generator = libROM.BasisGenerator(options, False, "basis.h5", Database.formats.HDF5) 71 | generator.takeSample(np.array([1.0, 2.0, 3.0])) 72 | spatial_basis = generator.getSpatialBasis() 73 | expected_spatial_basis = np.array([[-0.2672612419124243], [-0.5345224838248487], [-0.8017837257372731], [-6.4e-323]]) 74 | assert np.allclose(spatial_basis, expected_spatial_basis) 75 | 76 | def test_getTemporalBasis(): 77 | options = libROM.Options(4, 20, True, True) 78 | generator = libROM.BasisGenerator(options, False, "basis.h5", Database.formats.HDF5) 79 | generator.takeSample(np.array([1.0, 2.0, 3.0])) 80 | temporal_basis = generator.getTemporalBasis() 81 | expected_temporal_basis = np.array([[-1.0]]) 82 | assert np.allclose(temporal_basis, expected_temporal_basis) 83 | 84 | def test_getSingularValues(): 85 | options = libROM.Options(4, 20, True, True) 86 | generator = libROM.BasisGenerator(options, False, "basis.h5", Database.formats.HDF5) 87 | generator.takeSample(np.array([1.0, 2.0, 3.0])) 88 | singular_values = generator.getSingularValues() 89 | assert(np.array_equal(singular_values.getData(),[3.7416573867739418])) 90 | 91 | def test_getSnapshotMatrix(): 92 | options = libROM.Options(4, 20, True, True) 93 | generator = libROM.BasisGenerator(options, False, "basis.h5", Database.formats.HDF5) 94 | generator.takeSample(np.array([1.0, 2.0, 3.0])) 95 | snapshot_matrix = generator.getSnapshotMatrix() 96 | expected_snapshot_basis = np.array([[1.0], [2.0], [3.0], [5.6e-322]]) 97 | assert np.allclose(snapshot_matrix, expected_snapshot_basis) 98 | 99 | def test_getNumSamples(): 100 | options = libROM.Options(4, 20, True, True) 101 | generator = libROM.BasisGenerator(options, False, "basis.h5", Database.formats.HDF5) 102 | num_samples = generator.getNumSamples() 103 | assert num_samples == 0 104 | 105 | if __name__ == "__main__": 106 | pytest.main() -------------------------------------------------------------------------------- /tests/test_pyBasisReader.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import pytest 3 | try: 4 | # import pip-installed package 5 | import pylibROM 6 | import pylibROM.linalg as libROM 7 | from pylibROM.utils import Database 8 | except ModuleNotFoundError: 9 | # If pip-installed package is not found, import cmake-built package 10 | sys.path.append("../build") 11 | import _pylibROM as pylibROM 12 | import _pylibROM.linalg as libROM 13 | from _pylibROM.utils import Database 14 | import numpy as np 15 | 16 | options = libROM.Options(4, 20, True, True) 17 | options.static_svd_preserve_snapshot = True 18 | generator = libROM.BasisGenerator(options, False, "basis.h5", Database.formats.HDF5) 19 | result = generator.takeSample(np.array([1.0, 2.0, 3.0])) 20 | base_file_name = "test_basisreader_file" 21 | basis_writer = libROM.BasisWriter(generator, base_file_name, Database.formats.HDF5) 22 | basis_writer.writeBasis("basis") 23 | del basis_writer 24 | generator.writeSnapshot() 25 | generator.endSamples() 26 | del generator 27 | 28 | 29 | def test_getDim(): 30 | basis_reader = libROM.BasisReader("test_basisreader_file", Database.formats.HDF5) 31 | dim = basis_reader.getDim("basis") 32 | assert dim == 4 33 | 34 | 35 | def test_getNumSamples(): 36 | basis_reader = libROM.BasisReader("test_basisreader_file", Database.formats.HDF5) 37 | num_samples = basis_reader.getNumSamples("basis") 38 | assert num_samples == 1 39 | 40 | 41 | def test_getSpatialBasis(): 42 | options = libROM.Options(4, 20, True, True) 43 | options.static_svd_preserve_snapshot = True 44 | generator = libROM.BasisGenerator(options, False, "basis.h5", Database.formats.HDF5) 45 | result = generator.takeSample(np.array([1.0, 2.0, 3.0])) 46 | base_file_name = "test_basisreader_file" 47 | basis_writer = libROM.BasisWriter(generator, base_file_name, Database.formats.HDF5) 48 | basis_writer.writeBasis("basis") 49 | del basis_writer 50 | generator.writeSnapshot() 51 | generator.endSamples() 52 | del generator 53 | basis_reader = libROM.BasisReader("test_basisreader_file", Database.formats.HDF5) 54 | 55 | spatial_basis1 = basis_reader.getSpatialBasis() 56 | assert(np.allclose(spatial_basis1.getData(),[[-0.2672612419124243], [-0.5345224838248487], [-0.8017837257372731], [-4.44659081e-323]])) 57 | 58 | spatial_basis2 = basis_reader.getSpatialBasis(1) 59 | assert(np.allclose(spatial_basis2.getData(), [[-0.2672612419124243], [-0.5345224838248487], [-0.8017837257372731], [-4.44659081e-323]])) 60 | 61 | spatial_basis3 = basis_reader.getSpatialBasis(1, 1) 62 | assert(np.allclose(spatial_basis3.getData(), [[-0.2672612419124243], [-0.5345224838248487], [-0.8017837257372731], [-4.44659081e-323]])) 63 | 64 | spatial_basis4 = basis_reader.getSpatialBasis(0.7) 65 | assert(np.allclose(spatial_basis4.getData(), [[-0.2672612419124243], [-0.5345224838248487], [-0.8017837257372731],[-4.44659081e-323]])) 66 | 67 | 68 | def test_getTemporalBasis(): 69 | basis_reader = libROM.BasisReader("test_basisreader_file", Database.formats.HDF5) 70 | 71 | temporal_basis1 = basis_reader.getTemporalBasis() 72 | assert(np.array_equal(temporal_basis1.getData(), [[-1.0]])) 73 | 74 | temporal_basis2 = basis_reader.getTemporalBasis(1) 75 | assert(np.array_equal(temporal_basis2.getData(), [[-1.0]])) 76 | 77 | temporal_basis3 = basis_reader.getTemporalBasis(1, 1) 78 | assert(np.array_equal(temporal_basis3.getData(), [[-1.0]])) 79 | 80 | temporal_basis4 = basis_reader.getTemporalBasis(0.7) 81 | assert(np.array_equal(temporal_basis4.getData(), [[-1.0]])) 82 | 83 | 84 | def test_getSingularValues(): 85 | basis_reader = libROM.BasisReader("test_basisreader_file", Database.formats.HDF5) 86 | 87 | singular_values1 = basis_reader.getSingularValues() 88 | assert(np.array_equal(singular_values1.getData(), [3.7416573867739418])) 89 | 90 | singular_values2 = basis_reader.getSingularValues(0.7) 91 | assert(np.array_equal(singular_values2.getData(), [3.7416573867739418])) 92 | 93 | 94 | 95 | def test_getSnapshotMatrix(): 96 | basis_reader = libROM.BasisReader("basis.h5_snapshot", Database.formats.HDF5) 97 | 98 | snapshot_matrix1 = basis_reader.getSnapshotMatrix() 99 | assert(np.allclose(snapshot_matrix1.getData(),[[1.0], [2.0], [3.0], [0.0]])) 100 | 101 | snapshot_matrix2 = basis_reader.getSnapshotMatrix(1) 102 | assert(np.allclose(snapshot_matrix2.getData(), [[1.0], [2.0], [3.0], [0.0]])) 103 | 104 | snapshot_matrix3 = basis_reader.getSnapshotMatrix(1, 1) 105 | assert(np.allclose(snapshot_matrix3.getData(), [[1.0], [2.0], [3.0], [0.0]])) 106 | 107 | 108 | if __name__ == "__main__": 109 | pytest.main() 110 | -------------------------------------------------------------------------------- /tests/test_pyBasisWriter.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import pytest 3 | try: 4 | # import pip-installed package 5 | import pylibROM 6 | import pylibROM.linalg as libROM 7 | from pylibROM.utils import Database 8 | except ModuleNotFoundError: 9 | # If pip-installed package is not found, import cmake-built package 10 | sys.path.append("../build") 11 | import _pylibROM as pylibROM 12 | import _pylibROM.linalg as libROM 13 | from _pylibROM.utils import Database 14 | import numpy as np 15 | 16 | def test_writeBasis(): 17 | options = libROM.Options(4, 20, True, True) 18 | generator = libROM.BasisGenerator(options, False, "basis.h5", Database.formats.HDF5) 19 | result = generator.takeSample(np.array([1.0, 2.0, 3.0])) 20 | base_file_name = "basis_file" 21 | basis_writer = libROM.BasisWriter(generator, base_file_name, Database.formats.HDF5) 22 | basis_writer.writeBasis("basis") 23 | 24 | if __name__ == "__main__": 25 | pytest.main() 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /tests/test_pyDEIM.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import pytest 3 | sys.path.append("../build") 4 | import _pylibROM.linalg as linalg 5 | import numpy as np 6 | import _pylibROM.hyperreduction as hyperreduction 7 | 8 | 9 | def test_deim(): 10 | 11 | orthonormal_mat = np.array([ 12 | [-0.1067, -0.4723, -0.4552, 0.1104, -0.2337], 13 | [0.1462, 0.6922, -0.2716, 0.1663, 0.3569], 14 | [0.4087, -0.3437, 0.4952, -0.3356, 0.3246], 15 | [0.2817, -0.0067, -0.0582, -0.0034, 0.0674], 16 | [0.5147, 0.1552, -0.1635, -0.3440, -0.3045], 17 | [-0.4628, 0.0141, -0.1988, -0.5766, 0.0150], 18 | [-0.2203, 0.3283, 0.2876, -0.4597, -0.1284], 19 | [-0.0275, 0.1202, -0.0924, -0.2290, -0.3808], 20 | [0.4387, -0.0199, -0.3338, -0.1711, -0.2220], 21 | [0.0101, 0.1807, 0.4488, 0.3219, -0.6359] 22 | ]) 23 | 24 | DEIM_true_ans = np.array([ 25 | -0.295811, -0.264874, 1.02179, -1.05194, -0.554046, 26 | -0.270643, 1.05349, 0.119162, 0.541832, 0.646459, 27 | -1.33334, -0.874864, -0.276067, -0.27327, 0.124747, 28 | 0.672776, 0.538704, -0.735484, -0.794417, 0.388543, 29 | -0.682073, -0.049598, -0.51706, -0.457748, -1.11295 30 | ]) 31 | 32 | num_cols = 5 33 | num_rows = 10 34 | 35 | u = linalg.Matrix(orthonormal_mat,False,False) 36 | f_sampled_row_true_ans = [0, 1, 4, 5, 9] 37 | f_basis_sampled_inv = linalg.Matrix(num_cols, num_cols,False) 38 | 39 | f_sampled_row,f_sampled_rows_per_proc= hyperreduction.DEIM(u, num_cols,f_basis_sampled_inv, 0, 1) 40 | assert np.all(f_sampled_row == f_sampled_row_true_ans) 41 | 42 | l2_norm_diff = 0.0 43 | for i in range(num_cols): 44 | for j in range(num_cols): 45 | l2_norm_diff += abs(DEIM_true_ans[i * num_cols + j] - f_basis_sampled_inv[i, j]) ** 2 46 | l2_norm_diff = np.sqrt(l2_norm_diff) 47 | assert l2_norm_diff < 1e-5 48 | 49 | def test_deim_decreased_used_basis_vectors(): 50 | orthonormal_mat = np.array([ 51 | [-0.1067, -0.4723, -0.4552, 0.1104, -0.2337], 52 | [0.1462, 0.6922, -0.2716, 0.1663, 0.3569], 53 | [0.4087, -0.3437, 0.4952, -0.3356, 0.3246], 54 | [0.2817, -0.0067, -0.0582, -0.0034, 0.0674], 55 | [0.5147, 0.1552, -0.1635, -0.3440, -0.3045], 56 | [-0.4628, 0.0141, -0.1988, -0.5766, 0.0150], 57 | [-0.2203, 0.3283, 0.2876, -0.4597, -0.1284], 58 | [-0.0275, 0.1202, -0.0924, -0.2290, -0.3808], 59 | [0.4387, -0.0199, -0.3338, -0.1711, -0.2220], 60 | [0.0101, 0.1807, 0.4488, 0.3219, -0.6359] 61 | ]) 62 | 63 | DEIM_true_ans = np.array([ 64 | -0.331632, -0.690455, 2.07025, 65 | -0.541131, 1.17546, -0.446068, 66 | -1.55764, -1.05777, -0.022448 67 | ]) 68 | 69 | num_cols = 5 70 | num_rows = 10 71 | num_basis_vectors_used = 3 72 | 73 | u = linalg.Matrix(orthonormal_mat,False,False) 74 | f_sampled_row_true_ans = [0, 1, 4] 75 | f_basis_sampled_inv = linalg.Matrix(num_basis_vectors_used, num_basis_vectors_used,False) 76 | 77 | f_sampled_row,f_sampled_rows_per_proc = hyperreduction.DEIM(u, num_basis_vectors_used, 78 | f_basis_sampled_inv, 0, 1) 79 | 80 | assert np.all(f_sampled_row == f_sampled_row_true_ans) 81 | 82 | l2_norm_diff = 0.0 83 | for i in range(num_basis_vectors_used): 84 | for j in range(num_basis_vectors_used): 85 | l2_norm_diff += abs(DEIM_true_ans[i * num_basis_vectors_used + j] - f_basis_sampled_inv[i, j]) ** 2 86 | l2_norm_diff = np.sqrt(l2_norm_diff) 87 | assert l2_norm_diff < 1e-5 88 | 89 | if __name__ == "__main__": 90 | pytest.main() 91 | 92 | 93 | 94 | 95 | -------------------------------------------------------------------------------- /tests/test_pyDMD.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | import numpy as np 3 | import sys 4 | try: 5 | # import pip-installed package 6 | import pylibROM 7 | import pylibROM.linalg as linalg 8 | import pylibROM.algo as algo 9 | import pylibROM.utils as utils 10 | except ModuleNotFoundError: 11 | # If pip-installed package is not found, import cmake-built package 12 | sys.path.append("../build") 13 | import _pylibROM as pylibROM 14 | import _pylibROM.linalg as linalg 15 | import _pylibROM.algo as algo 16 | import _pylibROM.utils as utils 17 | 18 | def test_DMD(): 19 | from mpi4py import MPI 20 | d_rank = MPI.COMM_WORLD.Get_rank() 21 | d_num_procs = MPI.COMM_WORLD.Get_size() 22 | 23 | num_total_rows = 5 24 | d_num_rows = utils.split_dimension(num_total_rows, MPI.COMM_WORLD) 25 | num_total_rows_check, row_offset = utils.get_global_offsets(d_num_rows, MPI.COMM_WORLD) 26 | assert(num_total_rows == num_total_rows_check) 27 | 28 | samples = [[0.5377, 1.8339, -2.2588, 0.8622, 0.3188], 29 | [-1.3077, -0.4336, 0.3426, 3.5784, 2.7694], 30 | [-1.3499, 3.0349, 0.7254, -0.0631, 0.7147]] 31 | prediction_baseline = [-0.4344, -0.0974, 0.0542, 1.2544, 0.9610] 32 | 33 | dmd = algo.DMD(d_num_rows, 1.0) 34 | for k, sample in enumerate(samples): 35 | dmd.takeSample(sample[row_offset[d_rank]:row_offset[d_rank]+d_num_rows], k * 1.0) 36 | 37 | dmd.train(2) 38 | result = dmd.predict(3.0) 39 | # print("rank: %d, " % d_rank, result.getData()) 40 | assert np.allclose(result.getData(), prediction_baseline[row_offset[d_rank]:row_offset[d_rank]+d_num_rows], atol=1e-3) 41 | 42 | dmd.save("test_DMD") 43 | dmd_load = algo.DMD("test_DMD") 44 | result_load = dmd_load.predict(3.0) 45 | 46 | assert np.allclose(result_load.getData(), prediction_baseline[row_offset[d_rank]:row_offset[d_rank]+d_num_rows], atol=1e-3) 47 | 48 | if __name__ == '__main__': 49 | pytest.main() 50 | -------------------------------------------------------------------------------- /tests/test_pyGNAT.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import pytest 3 | sys.path.append("../build") 4 | import _pylibROM.linalg as linalg 5 | import numpy as np 6 | import _pylibROM.hyperreduction as hyperreduction 7 | 8 | 9 | def test_GNAT(): 10 | orthonormal_mat = np.array([ 11 | [-0.1067, -0.4723, -0.4552, 0.1104, -0.2337], 12 | [0.1462, 0.6922, -0.2716, 0.1663, 0.3569], 13 | [0.4087, -0.3437, 0.4952, -0.3356, 0.3246], 14 | [0.2817, -0.0067, -0.0582, -0.0034, 0.0674], 15 | [0.5147, 0.1552, -0.1635, -0.3440, -0.3045], 16 | [-0.4628, 0.0141, -0.1988, -0.5766, 0.0150], 17 | [-0.2203, 0.3283, 0.2876, -0.4597, -0.1284], 18 | [-0.0275, 0.1202, -0.0924, -0.2290, -0.3808], 19 | [0.4387, -0.0199, -0.3338, -0.1711, -0.2220], 20 | [0.0101, 0.1807, 0.4488, 0.3219, -0.6359] 21 | ]) 22 | 23 | GNAT_true_ans = np.array([ 24 | -0.295811, -0.264874, 1.02179, -1.05194, -0.554046, 25 | -0.270643, 1.05349, 0.119162, 0.541832, 0.646459, 26 | -1.33334, -0.874864, -0.276067, -0.27327, 0.124747, 27 | 0.672776, 0.538704, -0.735484, -0.794417, 0.388543, 28 | -0.682073, -0.049598, -0.51706, -0.457748, -1.11295 29 | ]) 30 | 31 | num_cols = 5 32 | num_rows = 10 33 | 34 | u = linalg.Matrix(orthonormal_mat,False,False) 35 | f_sampled_row=[0,0,0,0,0] 36 | f_sampled_row_true_ans = [0, 1, 4, 5, 9] 37 | f_sampled_rows_per_proc = [0] 38 | f_basis_sampled_inv = linalg.Matrix(num_cols, num_cols,False) 39 | f_sampled_row_result,f_sampled_rows_per_proc= hyperreduction.GNAT(u, num_cols,f_basis_sampled_inv, 0, 1) 40 | assert np.all(f_sampled_row_result == f_sampled_row_true_ans) 41 | 42 | l2_norm_diff = 0.0 43 | for i in range(num_cols): 44 | for j in range(num_cols): 45 | l2_norm_diff += abs(GNAT_true_ans[i * num_cols + j] - f_basis_sampled_inv[i, j]) ** 2 46 | l2_norm_diff = np.sqrt(l2_norm_diff) 47 | assert l2_norm_diff < 1e-5 48 | 49 | def test_GNAT_oversampling(): 50 | orthonormal_mat = np.array([ 51 | [-0.1067, -0.4723, -0.4552, 0.1104, -0.2337], 52 | [0.1462, 0.6922, -0.2716, 0.1663, 0.3569], 53 | [0.4087, -0.3437, 0.4952, -0.3356, 0.3246], 54 | [0.2817, -0.0067, -0.0582, -0.0034, 0.0674], 55 | [0.5147, 0.1552, -0.1635, -0.3440, -0.3045], 56 | [-0.4628, 0.0141, -0.1988, -0.5766, 0.0150], 57 | [-0.2203, 0.3283, 0.2876, -0.4597, -0.1284], 58 | [-0.0275, 0.1202, -0.0924, -0.2290, -0.3808], 59 | [0.4387, -0.0199, -0.3338, -0.1711, -0.2220], 60 | [0.0101, 0.1807, 0.4488, 0.3219, -0.6359] 61 | ]) 62 | 63 | GNAT_true_ans = np.array([ 64 | -0.111754, -0.472181, -0.454143, 0.110436, -0.234925, 65 | 0.169535, 0.691715, -0.276502, 0.166065, 0.362544, 66 | 0.443111, -0.344589, 0.488125, -0.336035, 0.332789, 67 | 0.556025, 0.154167, -0.172054, -0.344493, -0.294606, 68 | -0.498551, 0.0149608,-0.191435, -0.576216, 0.00647047, 69 | -0.247487, 0.328931, 0.293216, -0.459384, -0.134887, 70 | -0.036157, 0.120386, -0.0906109,-0.228902, -0.382862, 71 | 0.478391, -0.0208761,-0.342018, -0.171577, -0.2125, 72 | -0.0109879, 0.181169, 0.453212, 0.322187, -0.640965 73 | ]) 74 | 75 | num_cols = 5 76 | num_rows = 10 77 | num_samples = 9 78 | 79 | u = linalg.Matrix(orthonormal_mat,False,False) 80 | f_sampled_row = np.array([0,0,0,0,0,0,0,0,0]) 81 | f_sampled_row_true_ans = [0, 1, 2, 4, 5, 6, 7, 8, 9] 82 | f_sampled_rows_per_proc = [0] 83 | f_basis_sampled_inv = linalg.Matrix(num_samples, num_cols,False) 84 | 85 | f_sampled_row,f_sampled_rows_per_proc = hyperreduction.GNAT(u,num_cols,f_basis_sampled_inv, 0, 1,num_samples) 86 | 87 | assert np.all(f_sampled_row == f_sampled_row_true_ans) 88 | 89 | l2_norm_diff = 0.0 90 | for i in range(num_samples): 91 | for j in range(num_cols): 92 | l2_norm_diff += abs(GNAT_true_ans[i * num_cols + j] - f_basis_sampled_inv[i, j]) ** 2 93 | l2_norm_diff = np.sqrt(l2_norm_diff) 94 | assert l2_norm_diff < 1e-5 95 | 96 | if __name__ == "__main__": 97 | pytest.main() -------------------------------------------------------------------------------- /tests/test_pyGreedyCustomSampler.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import pytest 3 | import numpy as np 4 | import sys 5 | try: 6 | # import pip-installed package 7 | import pylibROM.linalg as linalg 8 | import pylibROM.algo.greedy as greedy 9 | except ModuleNotFoundError: 10 | # If pip-installed package is not found, import cmake-built package 11 | sys.path.append("../build") 12 | import _pylibROM.linalg as linalg 13 | import _pylibROM.algo.greedy as greedy 14 | 15 | from mpi4py import MPI 16 | 17 | 18 | def test_greedy_custom_sampler_centroid(): 19 | paramPoints = [1.0, 3.0, 6.0] 20 | caromGreedySampler = greedy.GreedyCustomSampler(paramPoints, False, 0.1, 1, 1, 2, 3, "", "", True, 1, True) 21 | nextPointToSample = caromGreedySampler.getNextParameterPoint() 22 | 23 | assert nextPointToSample.dim() == 1 24 | assert nextPointToSample.item(0) == 3.0 25 | 26 | caromGreedySampler.getNextPointRequiringRelativeError() 27 | caromGreedySampler.setPointRelativeError(100.0) 28 | 29 | localPoint = caromGreedySampler.getNextPointRequiringErrorIndicator() 30 | assert localPoint.point is not None 31 | assert localPoint.point.dim() == 1 32 | assert localPoint.point.item(0) == 3.0 33 | assert localPoint.localROM is not None 34 | 35 | caromGreedySampler.setPointErrorIndicator(1.0, 1) 36 | firstPoint = caromGreedySampler.getNextPointRequiringErrorIndicator() 37 | assert firstPoint.point is not None 38 | assert firstPoint.point.dim() == 1 39 | assert firstPoint.point.item(0) == 1.0 40 | 41 | caromGreedySampler.setPointErrorIndicator(100.0, 1) 42 | secondPoint = caromGreedySampler.getNextPointRequiringErrorIndicator() 43 | assert secondPoint.point is not None 44 | assert secondPoint.point.dim() == 1 45 | assert secondPoint.point.item(0) == 6.0 46 | 47 | caromGreedySampler.setPointErrorIndicator(50.0, 1) 48 | nextPointToSample = caromGreedySampler.getNextParameterPoint() 49 | assert nextPointToSample.dim() == 1 50 | assert nextPointToSample.item(0) == firstPoint.point.item(0) 51 | 52 | caromGreedySampler.getNextPointRequiringRelativeError() 53 | caromGreedySampler.setPointRelativeError(100.0) 54 | 55 | firstPoint = caromGreedySampler.getNextPointRequiringErrorIndicator() 56 | nextPointToSample = caromGreedySampler.getNextParameterPoint() 57 | assert nextPointToSample.dim() == 1 58 | assert nextPointToSample.item(0) == paramPoints[2] 59 | 60 | caromGreedySampler.getNextPointRequiringRelativeError() 61 | caromGreedySampler.setPointRelativeError(100.0) 62 | 63 | firstPoint = caromGreedySampler.getNextPointRequiringErrorIndicator() 64 | 65 | 66 | def test_greedy_custom_sampler_multi_dim_centroid(): 67 | item0 = linalg.Vector(2, False) 68 | item0[0] = 1.0 69 | item0[1] = 11.0 70 | 71 | item1 = linalg.Vector(2, False) 72 | item1[0] = 3.0 73 | item1[1] = 13.0 74 | 75 | item2 = linalg.Vector(2, False) 76 | item2[0] = 6.0 77 | item2[1] = 16.0 78 | 79 | paramPoints = [item0, item1, item2] 80 | 81 | caromGreedySampler = greedy.GreedyCustomSampler(paramPoints, False, 0.1, 1, 1, 2, 3, "", "", True, 1, True) 82 | 83 | nextPointToSample = caromGreedySampler.getNextParameterPoint() 84 | assert nextPointToSample.dim() == 2 85 | assert nextPointToSample.item(0) == 3.0 86 | assert nextPointToSample.item(1) == 13.0 87 | 88 | caromGreedySampler.getNextPointRequiringRelativeError() 89 | caromGreedySampler.setPointRelativeError(100.0) 90 | 91 | localPoint = caromGreedySampler.getNextPointRequiringErrorIndicator() 92 | 93 | assert localPoint.point is not None 94 | assert localPoint.point.dim() == 2 95 | assert localPoint.point.item(0) == 3.0 96 | assert localPoint.point.item(1) == 13.0 97 | assert localPoint.localROM is not None 98 | 99 | caromGreedySampler.setPointErrorIndicator(1.0, 1) 100 | 101 | firstPoint = caromGreedySampler.getNextPointRequiringErrorIndicator() 102 | assert firstPoint.point is not None 103 | assert firstPoint.point.dim() == 2 104 | assert firstPoint.point.item(0) == 1.0 105 | assert firstPoint.point.item(1) == 11.0 106 | 107 | caromGreedySampler.setPointErrorIndicator(100.0, 1) 108 | secondPoint = caromGreedySampler.getNextPointRequiringErrorIndicator() 109 | assert secondPoint.point is not None 110 | assert secondPoint.point.dim() == 2 111 | assert secondPoint.point.item(0) == 6.0 112 | assert secondPoint.point.item(1) == 16.0 113 | 114 | caromGreedySampler.setPointErrorIndicator(50.0, 1) 115 | nextPointToSample = caromGreedySampler.getNextParameterPoint() 116 | assert nextPointToSample.dim() == 2 117 | assert nextPointToSample.item(0) == firstPoint.point.item(0) 118 | assert nextPointToSample.item(1) == firstPoint.point.item(1) 119 | 120 | caromGreedySampler.getNextPointRequiringRelativeError() 121 | caromGreedySampler.setPointRelativeError(100.0) 122 | 123 | firstPoint = caromGreedySampler.getNextPointRequiringErrorIndicator() 124 | nextPointToSample = caromGreedySampler.getNextParameterPoint() 125 | assert nextPointToSample.dim() == 2 126 | assert nextPointToSample.item(0) == item2.item(0) 127 | assert nextPointToSample.item(1) == item2.item(1) 128 | 129 | tmp = caromGreedySampler.getNextPointRequiringRelativeError() 130 | assert tmp.point is None 131 | assert tmp.localROM is None 132 | 133 | caromGreedySampler.setPointRelativeError(100.0) 134 | firstPoint = caromGreedySampler.getNextPointRequiringErrorIndicator() 135 | 136 | 137 | def test_greedy_save_and_load(): 138 | paramPoints = [1.0, 2.0, 3.0, 99.0, 100., 101.0] 139 | 140 | caromGreedySampler = greedy.GreedyCustomSampler(paramPoints, False, 0.1, 1, 1, 3, 4, "", "", False, 1, True) 141 | caromGreedySampler.save("greedy_test") 142 | 143 | caromGreedySamplerLoad = greedy.GreedyCustomSampler("greedy_test") 144 | caromGreedySamplerLoad.save("greedy_test_LOAD") 145 | 146 | pointToFindNearestROM = linalg.Vector(1, False) 147 | pointToFindNearestROM[0] = 1.0 148 | 149 | closestROM = caromGreedySampler.getNearestROM(pointToFindNearestROM) 150 | closestROMLoad = caromGreedySamplerLoad.getNearestROM(pointToFindNearestROM) 151 | 152 | # there were no points sampled, so closestROM should be None 153 | assert closestROM is None 154 | assert closestROM == closestROMLoad 155 | 156 | nextPointToSample = caromGreedySampler.getNextParameterPoint() 157 | nextPointToSampleLoad = caromGreedySamplerLoad.getNextParameterPoint() 158 | 159 | assert nextPointToSample.dim() == nextPointToSampleLoad.dim() 160 | assert nextPointToSample.item(0) == nextPointToSampleLoad.item(0) 161 | 162 | 163 | def test_greedy_save_and_load_with_sample(): 164 | paramPoints = [1.0, 2.0, 3.0, 99.0, 100., 101.0] 165 | 166 | caromGreedySampler = greedy.GreedyCustomSampler(paramPoints, False, 0.1, 1, 1, 3, 4, "", "", False, 1, True) 167 | 168 | nextPointToSample = caromGreedySampler.getNextParameterPoint() 169 | assert nextPointToSample.dim() == 1 170 | assert nextPointToSample.item(0) == 3.0 171 | 172 | # save after sampling a point to test if sampled points are restored 173 | caromGreedySampler.save("greedy_test") 174 | 175 | caromGreedySamplerLoad = greedy.GreedyCustomSampler("greedy_test") 176 | caromGreedySamplerLoad.save("greedy_test_LOAD") 177 | 178 | pointToFindNearestROM = linalg.Vector(1, False) 179 | pointToFindNearestROM[0] = 1.0 180 | 181 | closestROM = caromGreedySampler.getNearestROM(pointToFindNearestROM) 182 | closestROMLoad = caromGreedySamplerLoad.getNearestROM(pointToFindNearestROM) 183 | 184 | assert closestROM is not None 185 | assert closestROM.dim() == 1 186 | assert closestROM.dim() == closestROMLoad.dim() 187 | assert closestROM.item(0) == 3.0 188 | assert closestROM.item(0) == closestROMLoad.item(0) 189 | 190 | nextPointToSample = caromGreedySampler.getNextParameterPoint() 191 | nextPointToSampleLoad = caromGreedySamplerLoad.getNextParameterPoint() 192 | 193 | assert nextPointToSample.dim() == nextPointToSampleLoad.dim() 194 | assert nextPointToSample.item(0) == nextPointToSampleLoad.item(0) 195 | 196 | if __name__ == '__main__': 197 | pytest.main() 198 | -------------------------------------------------------------------------------- /tests/test_pyHDFDatabaseMPIO.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import pytest 3 | import mpi4py 4 | try: 5 | # import pip-installed package 6 | import pylibROM 7 | import pylibROM.linalg as libROM 8 | from pylibROM.utils import Database, HDFDatabaseMPIO 9 | except ModuleNotFoundError: 10 | # If pip-installed package is not found, import cmake-built package 11 | sys.path.append("../build") 12 | import _pylibROM as pylibROM 13 | import _pylibROM.linalg as libROM 14 | from _pylibROM.utils import Database, HDFDatabaseMPIO 15 | import numpy as np 16 | 17 | nrow = 123 18 | ncol = 21 19 | threshold = 1.0e-13 20 | 21 | 22 | def test_HDFDatabase(): 23 | assert mpi4py.MPI.Is_initialized() 24 | comm = mpi4py.MPI.COMM_WORLD 25 | rank = comm.Get_rank() 26 | nproc = comm.Get_size() 27 | 28 | dim_rank = 2 29 | nrow_local = pylibROM.split_dimension(nrow, comm) 30 | global_dim, offsets = pylibROM.get_global_offsets(nrow_local, comm) 31 | assert global_dim == nrow 32 | 33 | rng = np.random.default_rng(1234) 34 | 35 | # distribute from a global matrix to keep the same system for different nproc 36 | snapshots = libROM.Matrix(nrow, ncol, False) 37 | for i in range(nrow): 38 | for j in range(ncol): 39 | snapshots[i, j] = rng.normal(0.0, 1.0) 40 | snapshots.distribute(nrow_local) 41 | 42 | options = libROM.Options(nrow_local, ncol, True) 43 | options.setMaxBasisDimension(nrow) 44 | options.setRandomizedSVD(False) 45 | options.setDebugMode(True) 46 | 47 | sampler = libROM.BasisGenerator(options, False, "test_basis", Database.formats.HDF5) 48 | 49 | sample = libROM.Vector(nrow_local, True) 50 | for s in range(ncol): 51 | for d in range(nrow_local): 52 | sample[d] = snapshots[d, s] 53 | sampler.takeSample(sample.getData()) 54 | 55 | sampler.writeSnapshot() 56 | snapshot = sampler.getSnapshotMatrix() 57 | sampler.endSamples() 58 | 59 | spatial_basis = sampler.getSpatialBasis() 60 | 61 | basis_reader = libROM.BasisReader("test_basis") 62 | spatial_basis1 = basis_reader.getSpatialBasis() 63 | assert spatial_basis.numRows() == spatial_basis1.numRows() 64 | assert spatial_basis.numColumns() == spatial_basis1.numColumns() 65 | np.testing.assert_array_almost_equal(spatial_basis.getData(), spatial_basis1.getData(), threshold) 66 | 67 | snapshot_reader = libROM.BasisReader("test_basis_snapshot") 68 | snapshot1 = snapshot_reader.getSnapshotMatrix() 69 | assert snapshot.numRows() == snapshot1.numRows() 70 | assert snapshot.numColumns() == snapshot1.numColumns() 71 | np.testing.assert_array_almost_equal(snapshot.getData(), snapshot1.getData(), threshold) 72 | 73 | 74 | def test_BaseMPIOCombination(): 75 | assert mpi4py.MPI.Is_initialized() 76 | comm = mpi4py.MPI.COMM_WORLD 77 | rank = comm.Get_rank() 78 | nproc = comm.Get_size() 79 | 80 | dim_rank = 2 81 | nrow_local = pylibROM.split_dimension(nrow, comm) 82 | global_dim, offsets = pylibROM.get_global_offsets(nrow_local, comm) 83 | assert global_dim == nrow 84 | 85 | base_name = "test_basis" 86 | mpio_name = "test_mpio" 87 | 88 | options = libROM.Options(nrow_local, ncol, True) 89 | options.setMaxBasisDimension(nrow) 90 | options.setRandomizedSVD(False) 91 | options.setDebugMode(True) 92 | 93 | sampler = libROM.BasisGenerator(options, False, mpio_name, Database.formats.HDF5_MPIO) 94 | 95 | sampler.loadSamples(base_name + "_snapshot", "snapshot", int(1e9), Database.formats.HDF5) 96 | sampler.writeSnapshot() 97 | snapshot = sampler.getSnapshotMatrix() 98 | 99 | snapshot_reader = libROM.BasisReader("test_basis_snapshot") 100 | snapshot1 = snapshot_reader.getSnapshotMatrix() 101 | assert snapshot.numRows() == snapshot1.numRows() 102 | assert snapshot.numColumns() == snapshot1.numColumns() 103 | np.testing.assert_array_almost_equal(snapshot.getData(), snapshot1.getData(), threshold) 104 | 105 | sampler.endSamples() 106 | spatial_basis = sampler.getSpatialBasis() 107 | 108 | basis_reader = libROM.BasisReader("test_basis") 109 | spatial_basis1 = basis_reader.getSpatialBasis() 110 | assert spatial_basis.numRows() == spatial_basis1.numRows() 111 | assert spatial_basis.numColumns() == spatial_basis1.numColumns() 112 | np.testing.assert_array_almost_equal(spatial_basis.getData(), spatial_basis1.getData(), threshold) 113 | 114 | 115 | def test_MPIOBaseCombination(): 116 | assert mpi4py.MPI.Is_initialized() 117 | comm = mpi4py.MPI.COMM_WORLD 118 | rank = comm.Get_rank() 119 | nproc = comm.Get_size() 120 | 121 | dim_rank = 2 122 | nrow_local = pylibROM.split_dimension(nrow, comm) 123 | global_dim, offsets = pylibROM.get_global_offsets(nrow_local, comm) 124 | assert global_dim == nrow 125 | 126 | base_name = "test_basis2" 127 | mpio_name = "test_mpio" 128 | 129 | options = libROM.Options(nrow_local, ncol, True) 130 | options.setMaxBasisDimension(nrow) 131 | options.setRandomizedSVD(False) 132 | options.setDebugMode(True) 133 | 134 | sampler = libROM.BasisGenerator(options, False, mpio_name, Database.formats.HDF5) 135 | 136 | sampler.loadSamples(mpio_name + "_snapshot", "snapshot", int(1e9), Database.formats.HDF5_MPIO) 137 | #sampler.writeSnapshot() 138 | snapshot = sampler.getSnapshotMatrix() 139 | 140 | snapshot_reader = libROM.BasisReader("test_basis_snapshot") 141 | snapshot1 = snapshot_reader.getSnapshotMatrix() 142 | assert snapshot.numRows() == snapshot1.numRows() 143 | assert snapshot.numColumns() == snapshot1.numColumns() 144 | np.testing.assert_array_almost_equal(snapshot.getData(), snapshot1.getData(), threshold) 145 | 146 | sampler.endSamples() 147 | spatial_basis = sampler.getSpatialBasis() 148 | 149 | basis_reader = libROM.BasisReader("test_basis") 150 | spatial_basis1 = basis_reader.getSpatialBasis() 151 | assert spatial_basis.numRows() == spatial_basis1.numRows() 152 | assert spatial_basis.numColumns() == spatial_basis1.numColumns() 153 | np.testing.assert_array_almost_equal(spatial_basis.getData(), spatial_basis1.getData(), threshold) 154 | 155 | 156 | def test_partialGetSpatialBasis(): 157 | assert mpi4py.MPI.Is_initialized() 158 | comm = mpi4py.MPI.COMM_WORLD 159 | rank = comm.Get_rank() 160 | nproc = comm.Get_size() 161 | 162 | nrow_local = pylibROM.split_dimension(nrow, comm) 163 | global_dim, offsets = pylibROM.get_global_offsets(nrow_local, comm) 164 | assert global_dim == nrow 165 | 166 | base_name = "test_basis" 167 | mpio_name = "test_mpio" 168 | 169 | basis_reader = libROM.BasisReader(base_name) 170 | spatial_basis = basis_reader.getSpatialBasis() 171 | 172 | basis_reader1 = libROM.BasisReader(mpio_name, Database.formats.HDF5_MPIO, nrow_local) 173 | spatial_basis1 = basis_reader1.getSpatialBasis() 174 | 175 | assert spatial_basis.numRows() == spatial_basis1.numRows() 176 | assert spatial_basis.numColumns() == spatial_basis1.numColumns() 177 | np.testing.assert_array_almost_equal(spatial_basis.getData(), spatial_basis1.getData(), threshold) 178 | 179 | 180 | if __name__ == "__main__": 181 | pytest.main() 182 | -------------------------------------------------------------------------------- /tests/test_pyIncrementalSVD.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | import sys 3 | try: 4 | # import pip-installed package 5 | import pylibROM 6 | import pylibROM.linalg as libROM 7 | import pylibROM.linalg.svd as SVD 8 | except ModuleNotFoundError: 9 | # If pip-installed package is not found, import cmake-built package 10 | sys.path.append("../build") 11 | import _pylibROM as pylibROM 12 | import _pylibROM.linalg as libROM 13 | import _pylibROM.linalg.svd as SVD 14 | import numpy as np 15 | 16 | def test_getSpatialBasis(): 17 | options = libROM.Options(3, 4) 18 | options.setMaxBasisDimension(3) 19 | options.setIncrementalSVD(1e-1, -1.0, -1.0, -1.0) 20 | incrementalSVD = SVD.IncrementalSVD(options, "irrelevant.txt" ) 21 | assert incrementalSVD.getSpatialBasis() is None 22 | 23 | def test_getTemporalBasis(): 24 | options = libROM.Options(3, 4) 25 | options.setMaxBasisDimension(3) 26 | options.setIncrementalSVD(1e-1, -1.0, -1.0, -1.0) 27 | incrementalSVD = SVD.IncrementalSVD(options, "irrelevant.txt" ) 28 | assert incrementalSVD.getTemporalBasis() is None 29 | 30 | def test_getSingularValues(): 31 | options = libROM.Options(3, 4) 32 | options.setMaxBasisDimension(3) 33 | options.setIncrementalSVD(1e-1, -1.0, -1.0, -1.0) 34 | incrementalSVD = SVD.IncrementalSVD(options, "irrelevant.txt" ) 35 | assert incrementalSVD.getSingularValues() is None 36 | 37 | def test_getSnapshotMatrix(): 38 | options = libROM.Options(3, 4) 39 | options.setMaxBasisDimension(3) 40 | options.setIncrementalSVD(1e-1, -1.0, -1.0, -1.0) 41 | incrementalSVD = SVD.IncrementalSVD(options, "irrelevant.txt" ) 42 | assert incrementalSVD.getSnapshotMatrix() is None 43 | 44 | def test_getDim(): 45 | options = libROM.Options(3, 4) 46 | options.setMaxBasisDimension(3) 47 | options.setIncrementalSVD(1e-1, -1.0, -1.0, -1.0) 48 | incrementalSVD = SVD.IncrementalSVD(options, "irrelevant.txt") 49 | assert incrementalSVD.getDim() == 3 50 | 51 | def test_getMaxNumSamples(): 52 | options = libROM.Options(3, 4) 53 | options.setMaxBasisDimension(3) 54 | options.setIncrementalSVD(1e-1, -1.0, -1.0, -1.0) 55 | incrementalSVD = SVD.IncrementalSVD(options, "irrelevant.txt" ) 56 | assert(incrementalSVD.getMaxNumSamples() == 4) 57 | 58 | def test_getNumSamples(): 59 | options = libROM.Options(3, 4) 60 | options.setMaxBasisDimension(3) 61 | options.setIncrementalSVD(1e-1, -1.0, -1.0, -1.0) 62 | incrementalSVD = SVD.IncrementalSVD(options, "irrelevant.txt" ) 63 | num_samples = incrementalSVD.getNumSamples() 64 | assert num_samples == 0 65 | 66 | if __name__ == '__main__': 67 | pytest.main() 68 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /tests/test_pyNNLS.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import pytest 3 | import numpy as np 4 | from scipy import optimize 5 | from mpi4py import MPI 6 | import _pylibROM.linalg as la 7 | 8 | #- parallelization setup 9 | comm = MPI.COMM_WORLD 10 | 11 | #- input setup 12 | A = np.random.rand(5,10) 13 | x = np.zeros((10,)) 14 | rhs_lb, rhs_ub = np.ones((5,))*(3.5-1e-5), np.ones((5,))*(3.5+1e-5) 15 | b = (rhs_lb+rhs_ub)/2 16 | sol,res = optimize.nnls(A,b) 17 | 18 | 19 | def test_getNumProcs(): 20 | nnls = la.NNLSSolver() 21 | assert nnls.getNumProcs() == comm.size 22 | 23 | def test_normalize_constraints(): 24 | const_tol = 1e-6 25 | 26 | # normalize constraints in NNLS 27 | nnls = la.NNLSSolver(const_tol=const_tol) 28 | At_lr,x_lr = la.Matrix(A.T.copy(),True,True),la.Vector(x.copy(),True,True) 29 | lb_lr, ub_lr = la.Vector(rhs_lb.copy(),False,True), la.Vector(rhs_ub.copy(),False,True) 30 | nnls.normalize_constraints(At_lr,lb_lr,ub_lr) 31 | 32 | # normalize constraints manually 33 | halfgap_target = const_tol*1e3 34 | halfgap = (rhs_ub-rhs_lb)/2 35 | b = (rhs_lb + rhs_ub)/2 36 | An = np.zeros_like(A) 37 | rhs_lbn, rhs_ubn = np.zeros_like(rhs_lb), np.zeros_like(rhs_ub) 38 | for i in range(len(A)): 39 | s = halfgap_target/halfgap 40 | An[i] = A[i]*s[i] 41 | rhs_lbn, rhs_ubn = b*s - halfgap_target, b*s + halfgap_target 42 | 43 | assert np.allclose(At_lr.getData(),An.T,rtol=1e-10) 44 | assert np.allclose(lb_lr.getData(),rhs_lbn,rtol=1e-10) 45 | assert np.allclose(ub_lr.getData(),rhs_ubn,rtol=1e-10) 46 | 47 | 48 | def test_solve_parallel_with_scalapack(): 49 | nnls = la.NNLSSolver() 50 | At_lr,x_lr = la.Matrix(A.T.copy(),True,True),la.Vector(x.copy(),True,True) 51 | lb_lr, ub_lr = la.Vector(rhs_lb.copy(),False,True), la.Vector(rhs_ub.copy(),False,True) 52 | 53 | nnls.solve_parallel_with_scalapack(At_lr,lb_lr,ub_lr,x_lr) 54 | 55 | assert np.allclose(sol,x_lr.getData(),rtol=1e-10) 56 | 57 | -------------------------------------------------------------------------------- /tests/test_pyOptions.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import pytest 3 | try: 4 | # import pip-installed package 5 | import pylibROM 6 | import pylibROM.linalg as libROM 7 | except ModuleNotFoundError: 8 | # If pip-installed package is not found, import cmake-built package 9 | sys.path.append("../build") 10 | import _pylibROM as pylibROM 11 | import _pylibROM.linalg as libROM 12 | import numpy as np 13 | 14 | def test_options_constructor_two_args(): 15 | options = libROM.Options(4, 20) 16 | assert options.dim == 4 17 | assert options.max_basis_dimension == 20 18 | assert options.max_num_samples == 20 19 | assert not options.update_right_SV 20 | assert not options.write_snapshots 21 | 22 | def test_options_constructor_all_args(): 23 | options = libROM.Options(4, 20, True, False) 24 | assert options.dim == 4 25 | assert options.max_basis_dimension == 20 26 | assert options.max_num_samples == 20 27 | assert options.update_right_SV 28 | assert not options.write_snapshots 29 | 30 | def test_setMaxBasisDimension(): 31 | options = libROM.Options(4, 5, True, False) 32 | options.setMaxBasisDimension(10) 33 | assert options.max_basis_dimension == 10 34 | 35 | def test_setSingularValueTolerance(): 36 | options = libROM.Options(4, 20, True, False) 37 | options.setSingularValueTol(0.01) 38 | assert options.singular_value_tol == 0.01 39 | 40 | def test_setDebugMode(): 41 | options = libROM.Options(4, 20, True, False) 42 | options.setDebugMode(True) 43 | assert options.debug_algorithm 44 | 45 | def test_setRandomizedSVD(): 46 | options = libROM.Options(4, 20, True, False) 47 | options.setRandomizedSVD(True, randomized_subspace_dim_=5, random_seed_=42) 48 | assert options.randomized 49 | assert options.randomized_subspace_dim == 5 50 | assert options.random_seed == 42 51 | 52 | def test_setIncrementalSVD(): 53 | options = libROM.Options(4, 20, True, False) 54 | options.setIncrementalSVD(linearity_tol_=0.001, initial_dt_=0.1, sampling_tol_=0.001, max_time_between_samples_=1.0, fast_update_=True, skip_linearly_dependent_=False) 55 | assert options.linearity_tol == 0.001 56 | assert options.initial_dt == 0.1 57 | assert options.sampling_tol == 0.001 58 | assert options.max_time_between_samples == 1.0 59 | assert options.fast_update 60 | assert not options.skip_linearly_dependent 61 | 62 | def test_setStateIO(): 63 | options = libROM.Options(4, 20, True, False) 64 | options.setStateIO(save_state_=True, restore_state_=False) 65 | assert options.save_state 66 | assert not options.restore_state 67 | 68 | def test_setSamplingTimeStepScale(): 69 | options = libROM.Options(4, 20, True, False) 70 | options.setSamplingTimeStepScale(min_sampling_time_step_scale_=0.5, sampling_time_step_scale_=1.0, max_sampling_time_step_scale_=2.0) 71 | assert options.min_sampling_time_step_scale == 0.5 72 | assert options.sampling_time_step_scale == 1.0 73 | assert options.max_sampling_time_step_scale == 2.0 74 | 75 | 76 | if __name__ == '__main__': 77 | pytest.main() -------------------------------------------------------------------------------- /tests/test_pyQDEIM.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import pytest 3 | sys.path.append("../build") 4 | import _pylibROM.linalg as linalg 5 | import numpy as np 6 | import _pylibROM.hyperreduction as hyperreduction 7 | 8 | 9 | def test_qdeim(): 10 | 11 | orthonormal_mat = np.array([ 12 | [-0.1067, -0.4723, -0.4552, 0.1104, -0.2337], 13 | [0.1462, 0.6922, -0.2716, 0.1663, 0.3569], 14 | [0.4087, -0.3437, 0.4952, -0.3356, 0.3246], 15 | [0.2817, -0.0067, -0.0582, -0.0034, 0.0674], 16 | [0.5147, 0.1552, -0.1635, -0.3440, -0.3045], 17 | [-0.4628, 0.0141, -0.1988, -0.5766, 0.0150], 18 | [-0.2203, 0.3283, 0.2876, -0.4597, -0.1284], 19 | [-0.0275, 0.1202, -0.0924, -0.2290, -0.3808], 20 | [0.4387, -0.0199, -0.3338, -0.1711, -0.2220], 21 | [0.0101, 0.1807, 0.4488, 0.3219, -0.6359] 22 | ]) 23 | 24 | QDEIM_true_ans = np.array([ 25 | 0.439578, 0.704765, 0.90859, -0.80199, 0.333326, 26 | 0.989496, -0.108636, 0.0666524, 0.626509, 0.341482, 27 | 0.195839, 0.938665, -0.634648, 0.425609, 0.807025, 28 | 0.437564, -0.00667263,-0.5862, -1.0578, 0.736468, 29 | 0.647878, 0.639428, -0.711286, -0.0697963, -0.527859 30 | ]) 31 | 32 | num_cols = 5 33 | num_rows = 10 34 | 35 | u = linalg.Matrix(orthonormal_mat,True,False) 36 | f_sampled_row_true_ans = [1, 2, 4, 6, 9] 37 | f_basis_sampled_inv = linalg.Matrix(num_cols, num_cols,False) 38 | 39 | f_sampled_row,f_sampled_rows_per_proc= hyperreduction.QDEIM(u, num_cols,f_basis_sampled_inv, 0, 1, num_cols) 40 | assert np.all(f_sampled_row == f_sampled_row_true_ans) 41 | 42 | l2_norm_diff = 0.0 43 | for i in range(num_cols): 44 | for j in range(num_cols): 45 | l2_norm_diff += abs(QDEIM_true_ans[i * num_cols + j] - f_basis_sampled_inv[i, j]) ** 2 46 | l2_norm_diff = np.sqrt(l2_norm_diff) 47 | assert l2_norm_diff < 1e-5 48 | 49 | def test_qdeim_gpode_oversampling(): 50 | orthonormal_mat = np.array([ 51 | [-0.1067, -0.4723, -0.4552, 0.1104, -0.2337], 52 | [0.1462, 0.6922, -0.2716, 0.1663, 0.3569], 53 | [0.4087, -0.3437, 0.4952, -0.3356, 0.3246], 54 | [0.2817, -0.0067, -0.0582, -0.0034, 0.0674], 55 | [0.5147, 0.1552, -0.1635, -0.3440, -0.3045], 56 | [-0.4628, 0.0141, -0.1988, -0.5766, 0.0150], 57 | [-0.2203, 0.3283, 0.2876, -0.4597, -0.1284], 58 | [-0.0275, 0.1202, -0.0924, -0.2290, -0.3808], 59 | [0.4387, -0.0199, -0.3338, -0.1711, -0.2220], 60 | [0.0101, 0.1807, 0.4488, 0.3219, -0.6359] 61 | ]) 62 | 63 | QDEIM_true_ans = np.array([ 64 | -0.114191, -0.464064, -0.460252, 0.0950032, -0.260738, 65 | 0.172884, 0.680565, -0.268109, 0.187266, 0.398005, 66 | 0.450012, -0.367566, 0.505419, -0.292346, 0.405863, 67 | 0.546255, 0.186697, -0.196538, -0.406346, -0.39806, 68 | -0.506112, 0.0401362, -0.210384, -0.624084, -0.0735944, 69 | -0.255659, 0.356138, 0.272739, -0.511115, -0.221413, 70 | 0.472064, 0.00019259, -0.357875, -0.211637, -0.279505, 71 | -0.0179827, 0.204459, 0.435683, 0.277904, -0.715033 72 | ]) 73 | 74 | num_cols = 5 75 | num_rows = 10 76 | num_samples = 8 77 | 78 | u = linalg.Matrix(orthonormal_mat,True,False) 79 | f_sampled_row = np.array([0,0,0,0,0,0,0,0]) 80 | f_sampled_row_true_ans = [0, 1, 2, 4, 5, 6, 8, 9] 81 | f_basis_sampled_inv = linalg.Matrix(num_samples,num_cols,False) 82 | 83 | f_sampled_row,f_sampled_rows_per_proc = hyperreduction.QDEIM(u, num_cols,f_basis_sampled_inv, 0, 1, num_samples) 84 | 85 | assert np.all(f_sampled_row == f_sampled_row_true_ans) 86 | 87 | l2_norm_diff = 0.0 88 | for i in range(num_samples): 89 | for j in range(num_cols): 90 | l2_norm_diff += abs(QDEIM_true_ans[i * num_cols + j] - f_basis_sampled_inv[i, j]) ** 2 91 | l2_norm_diff = np.sqrt(l2_norm_diff) 92 | assert l2_norm_diff < 1e-5 93 | 94 | if __name__ == "__main__": 95 | pytest.main() -------------------------------------------------------------------------------- /tests/test_pyQR.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import pytest 3 | import mpi4py 4 | import numpy as np 5 | try: 6 | # import pip-installed package 7 | import pylibROM 8 | import pylibROM.linalg as libROM 9 | except ModuleNotFoundError: 10 | # If pip-installed package is not found, import cmake-built package 11 | sys.path.append("../build") 12 | import _pylibROM as pylibROM 13 | import _pylibROM.linalg as libROM 14 | 15 | 16 | def test_MatrixQR(): 17 | assert mpi4py.MPI.Is_initialized() 18 | comm = mpi4py.MPI.COMM_WORLD 19 | rank = comm.Get_rank() 20 | num_procs = comm.Get_size() 21 | 22 | num_total_rows = 5 23 | num_columns = 3 24 | loc_num_rows = pylibROM.split_dimension(num_total_rows, comm) 25 | total_rows, row_offset = pylibROM.get_global_offsets(loc_num_rows, comm) 26 | assert total_rows == num_total_rows 27 | 28 | q_data = [ 29 | 3.08158946098238906153E-01, -9.49897947980619661301E-02, -4.50691774108525788911E-01, 30 | -1.43697905723455976457E-01, 9.53289043424090820622E-01, 8.77767692937209131898E-02, 31 | -2.23655845793717528158E-02, -2.10628953513210204207E-01, 8.42235962392685943989E-01, 32 | -7.29903965154318323805E-01, -1.90917141788945754488E-01, -2.77280930877637610266E-01, 33 | -5.92561353877168350834E-01, -3.74570084880578441089E-02, 5.40928141934190823137E-02 34 | ] 35 | 36 | r_data = [ 37 | -1.78651649346571794741E-01, 5.44387957786310106023E-01, -8.19588518467042281834E-01, 38 | 0.0, -3.13100149275943651084E-01, -9.50441422536040881122E-04, 39 | 0.0, 0.0, 5.72951792961765460355E-01 40 | ] 41 | 42 | exactQ = libROM.Matrix(loc_num_rows, num_columns, True) 43 | exactR = libROM.Matrix(np.asarray(r_data).reshape((3,3)), False, True) 44 | 45 | for i in range(loc_num_rows): 46 | for j in range(num_columns): 47 | exactQ[i,j] = q_data[((i + row_offset[rank]) * num_columns) + j] 48 | 49 | assert exactQ.numRows() == loc_num_rows 50 | assert exactQ.numColumns() == num_columns 51 | 52 | # Verify that the columns of Q are orthonormal 53 | id = exactQ.transposeMult(exactQ) 54 | assert id.numRows() == num_columns 55 | assert id.numColumns() == num_columns 56 | 57 | maxError = np.max(np.abs(id.getData() - np.eye(num_columns))) 58 | np.testing.assert_almost_equal(maxError, 0.0, 15) 59 | 60 | 61 | # Compute A = QR 62 | # A = exactQ.mult(exactR) # need PR28 fix for this syntax 63 | A = libROM.Matrix(num_columns, num_columns, True) 64 | exactQ.mult(exactR, A) 65 | 66 | # Factorize A 67 | QRfactors = A.qr_factorize() 68 | assert len(QRfactors) == 2 69 | 70 | Q = QRfactors[0] 71 | R = QRfactors[1] 72 | assert Q.numRows() == loc_num_rows 73 | assert Q.numColumns() == num_columns 74 | assert R.numRows() == num_columns 75 | assert R.numColumns() == num_columns 76 | 77 | # Verify that Q == -exactQ and R == -exactR 78 | maxError = np.max(np.abs(exactQ.getData() + Q.getData())) 79 | np.testing.assert_almost_equal(maxError, 0.0, 15) 80 | 81 | maxError = np.max(np.abs(exactR.getData() + R.getData())) 82 | np.testing.assert_almost_equal(maxError, 0.0, 15) 83 | 84 | 85 | if __name__ == '__main__': 86 | pytest.main() 87 | -------------------------------------------------------------------------------- /tests/test_pySTSampling.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import pytest 3 | sys.path.append("../build") 4 | import _pylibROM.linalg as linalg 5 | import numpy as np 6 | import _pylibROM.hyperreduction as hyperreduction 7 | 8 | 9 | @pytest.mark.skip("TODO") 10 | def test_SpaceTimeSampling(): 11 | # Prepare test data 12 | num_f_basis_vectors_used = 5 13 | num_cols = 5 14 | num_rows = 10 15 | num_t_samples_req=5 16 | num_s_samples_req= 10 17 | s_basis = linalg.Matrix(num_rows,num_cols,True,False) 18 | t_basis = linalg.Matrix(num_rows,num_cols,False,False) 19 | f_sampled_row = np.zeros(num_s_samples_req, dtype=np.int32) 20 | f_sampled_rows_per_proc = np.zeros(1, dtype=np.int32) 21 | s_basis_sampled = linalg.Matrix(num_s_samples_req,num_t_samples_req,False,False) 22 | myid = 0 23 | num_procs = 1 24 | 25 | t_samples= hyperreduction.SpaceTimeSampling(s_basis, t_basis, num_f_basis_vectors_used, 26 | f_sampled_row,f_sampled_rows_per_proc, s_basis_sampled, 27 | myid, num_procs,num_t_samples_req,num_s_samples_req,False) 28 | assert np.all(t_samples == [0, 1, 2, 3, 4]) 29 | assert np.all(f_sampled_row == [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) 30 | assert np.all(f_sampled_rows_per_proc == [10]) 31 | 32 | 33 | @pytest.mark.skip("TODO") 34 | def test_GetSampledSpaceTimeBasis(): 35 | t_samples = [1,2,3] 36 | t_basis = linalg.Matrix(3,5,True,False) 37 | t_basis.fill(2.0) 38 | s_basis_sampled = linalg.Matrix(2,5,False,False) 39 | s_basis_sampled.fill(3.0) 40 | f_basis_sampled_inv = linalg.Matrix(6, 2, False,False) 41 | hyperreduction.GetSampledSpaceTimeBasis(t_samples, t_basis, s_basis_sampled, f_basis_sampled_inv) 42 | assert np.allclose(f_basis_sampled_inv.getData(),[[1728.0, 6.0], [1728.0, 6.0], [4.751093e-318, 3.297888e-320], [1728.0, 6.0], [1728.0, 6.0], [4.751093e-318, 3.297888e-320]]) 43 | 44 | 45 | if __name__ == '__main__': 46 | pytest.main() 47 | 48 | -------------------------------------------------------------------------------- /tests/test_pySVD.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import pytest 3 | try: 4 | # import pip-installed package 5 | import pylibROM 6 | import pylibROM.linalg as libROM 7 | import pylibROM.linalg.svd as SVD 8 | except ModuleNotFoundError: 9 | # If pip-installed package is not found, import cmake-built package 10 | sys.path.append("../build") 11 | import _pylibROM as pylibROM 12 | import _pylibROM.linalg as libROM 13 | import _pylibROM.linalg.svd as SVD 14 | import numpy as np 15 | 16 | def test_getDim(): 17 | options = libROM.Options(4, 20, True, True) 18 | svd = SVD.SVD(options) 19 | dim = svd.getDim() 20 | assert dim == 4 21 | 22 | def test_getMaxNumSamples(): 23 | options = libROM.Options(4, 20, True, True) 24 | svd = SVD.SVD(options) 25 | assert(svd.getMaxNumSamples() == 20) 26 | 27 | def test_getNumSamples(): 28 | options = libROM.Options(4, 20, True, True) 29 | svd = SVD.SVD(options) 30 | num_samples = svd.getNumSamples() 31 | assert num_samples == 0 32 | 33 | if __name__ == '__main__': 34 | pytest.main() 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /tests/test_pyStaticSVD.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import pytest 3 | try: 4 | # import pip-installed package 5 | import pylibROM 6 | import pylibROM.linalg as libROM 7 | import pylibROM.linalg.svd as SVD 8 | except ModuleNotFoundError: 9 | # If pip-installed package is not found, import cmake-built package 10 | sys.path.append("../build") 11 | import _pylibROM as pylibROM 12 | import _pylibROM.linalg as libROM 13 | import _pylibROM.linalg.svd as SVD 14 | import numpy as np 15 | 16 | def test_getDim(): 17 | options = libROM.Options(3, 10, True, True) 18 | staticsvd=SVD.StaticSVD(options) 19 | dim = staticsvd.getDim() 20 | assert dim == 3 21 | 22 | def test_getNumSamples(): 23 | options = libROM.Options(4, 20, True, True) 24 | staticsvd = SVD.StaticSVD(options) 25 | num_samples = staticsvd.getNumSamples() 26 | assert num_samples == 0 27 | 28 | def test_getMaxNumSamples(): 29 | options = libROM.Options(4, 20, True, True) 30 | staticsvd = SVD.StaticSVD(options) 31 | assert(staticsvd.getMaxNumSamples() == 20) 32 | 33 | def test_takeSample(): 34 | options = libROM.Options(3, 10, True, True) 35 | staticsvd = SVD.StaticSVD(options) 36 | u_in = np.array([1.0, 2.0, 3.0, 4.0]) 37 | add_without_increase = False 38 | result = staticsvd.takeSample(u_in, add_without_increase) 39 | assert result == True 40 | 41 | def test_getSpatialBasis(): 42 | options = libROM.Options(3, 10, True, True) 43 | staticsvd = SVD.StaticSVD(options) 44 | u_in = np.array([1.0, 2.0, 3.0, 4.0]) 45 | add_without_increase = False 46 | staticsvd.takeSample(u_in, add_without_increase) 47 | spatial_basis = staticsvd.getSpatialBasis() 48 | assert(np.array_equal(spatial_basis.getData(), [[-0.2672612419124243], [-0.5345224838248487], [-0.8017837257372731]])) 49 | 50 | def test_getTemporalBasis(): 51 | options = libROM.Options(3, 10, True, True) 52 | staticsvd = SVD.StaticSVD(options) 53 | u_in = np.array([1.0, 2.0, 3.0, 4.0]) 54 | add_without_increase = False 55 | staticsvd.takeSample(u_in, add_without_increase) 56 | temporal_basis = staticsvd.getTemporalBasis() 57 | assert(np.array_equal(temporal_basis.getData(), [[-1.0]])) 58 | 59 | def test_getSingularValues(): 60 | options = libROM.Options(3, 10, True, True) 61 | staticsvd = SVD.StaticSVD(options) 62 | u_in = np.array([1.0, 2.0, 3.0, 4.0]) 63 | add_without_increase = False 64 | staticsvd.takeSample(u_in, add_without_increase) 65 | singular_values = staticsvd.getSingularValues() 66 | assert(np.array_equal(singular_values.getData(), [3.7416573867739418])) 67 | 68 | def test_getSnapshotMatrix(): 69 | options = libROM.Options(5, 10, True, True) 70 | staticsvd = SVD.StaticSVD(options) 71 | input_snapshot = np.array([[0.5377, 1.8339, -2.2588, 0.8622, 0.3188], 72 | [-1.3077, -0.4336, 0.3426, 3.5784, 2.7694], 73 | [-1.3499, 3.0349, 0.7254, -0.0631, 0.7147]]) 74 | input_snapshot = input_snapshot.T 75 | add_without_increase = False 76 | for k in range(input_snapshot.shape[1]): 77 | result = staticsvd.takeSample(input_snapshot[:,k], add_without_increase) 78 | snapshot_matrix = staticsvd.getSnapshotMatrix() 79 | assert(np.array_equal(snapshot_matrix, input_snapshot)) 80 | 81 | 82 | if __name__ == '__main__': 83 | pytest.main() 84 | 85 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /tests/test_pyUtilities.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import pytest 3 | sys.path.append("../build") 4 | import numpy as np 5 | import _pylibROM.hyperreduction as hyperreduction 6 | 7 | def test_Rowinfo(): 8 | row_info = hyperreduction.RowInfo() 9 | row_info.row_val = 3 10 | row_info.row = 42 11 | row_info.proc = 2 12 | 13 | assert row_info.row_val == 3 14 | assert row_info.row == 42 15 | assert row_info.proc == 2 16 | 17 | if __name__ == '__main__': 18 | pytest.main() --------------------------------------------------------------------------------