droute 0.5.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- droute-0.5.0/CHANGELOG.md +49 -0
- droute-0.5.0/CMakeLists.txt +526 -0
- droute-0.5.0/LICENSE +21 -0
- droute-0.5.0/MANIFEST.in +15 -0
- droute-0.5.0/PKG-INFO +213 -0
- droute-0.5.0/README.md +153 -0
- droute-0.5.0/SECURITY.md +72 -0
- droute-0.5.0/cmake/dmc_routeConfig.cmake.in +8 -0
- droute-0.5.0/include/dmc/ad_backend.hpp +183 -0
- droute-0.5.0/include/dmc/advanced_routing.hpp +1341 -0
- droute-0.5.0/include/dmc/bmi.hpp +479 -0
- droute-0.5.0/include/dmc/channel_geometry.hpp +393 -0
- droute-0.5.0/include/dmc/kernels_enzyme.hpp +2001 -0
- droute-0.5.0/include/dmc/network.hpp +319 -0
- droute-0.5.0/include/dmc/network_io.hpp +389 -0
- droute-0.5.0/include/dmc/parallel_routing.hpp +377 -0
- droute-0.5.0/include/dmc/router.hpp +2529 -0
- droute-0.5.0/include/dmc/runoff_forcing.hpp +626 -0
- droute-0.5.0/include/dmc/saint_venant_enzyme.hpp +1067 -0
- droute-0.5.0/include/dmc/saint_venant_router.hpp +834 -0
- droute-0.5.0/include/dmc/topology_nc.hpp +479 -0
- droute-0.5.0/include/dmc/types.hpp +197 -0
- droute-0.5.0/include/dmc/unified_router.hpp +855 -0
- droute-0.5.0/pyproject.toml +79 -0
- droute-0.5.0/python/bindings.cpp +1522 -0
- droute-0.5.0/python/droute/__init__.py +28 -0
- droute-0.5.0/python/droute/_version.py +3 -0
- droute-0.5.0/python/droute.egg-info/PKG-INFO +213 -0
- droute-0.5.0/python/droute.egg-info/SOURCES.txt +37 -0
- droute-0.5.0/python/droute.egg-info/dependency_links.txt +1 -0
- droute-0.5.0/python/droute.egg-info/not-zip-safe +1 -0
- droute-0.5.0/python/droute.egg-info/requires.txt +10 -0
- droute-0.5.0/python/droute.egg-info/top_level.txt +3 -0
- droute-0.5.0/python/pydmc_route.py +37 -0
- droute-0.5.0/python/test_routing_with_data.py +1360 -0
- droute-0.5.0/setup.cfg +4 -0
- droute-0.5.0/setup.py +83 -0
- droute-0.5.0/src/lib.cpp +41 -0
- droute-0.5.0/src/main.cpp +797 -0
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to dRoute will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [0.5.0] - 2025-12-27
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- Initial PyPI release
|
|
12
|
+
- Six routing methods: Muskingum-Cunge, Lag, IRF, KWT-Soft, Diffusive Wave, and Saint-Venant
|
|
13
|
+
- Dual AD backends: CoDiPack (tape-based) and Enzyme (source-to-source)
|
|
14
|
+
- Full river network topology support with tributaries and confluences
|
|
15
|
+
- mizuRoute compatibility for topology.nc files
|
|
16
|
+
- PyTorch integration for gradient-based optimization
|
|
17
|
+
- Python bindings via pybind11
|
|
18
|
+
- Comprehensive documentation and examples
|
|
19
|
+
- C++ test suite
|
|
20
|
+
|
|
21
|
+
### Changed
|
|
22
|
+
- **BREAKING**: Package renamed from `pydmc_route` to `droute`
|
|
23
|
+
- Install with: `pip install droute`
|
|
24
|
+
- Import with: `import droute`
|
|
25
|
+
- Backwards compatibility shim included (will be deprecated in v1.0.0)
|
|
26
|
+
- Unified version management across setup.py, pyproject.toml, and C++ extension
|
|
27
|
+
- Updated author information and repository URLs
|
|
28
|
+
- Improved error messages in package initialization
|
|
29
|
+
|
|
30
|
+
### Fixed
|
|
31
|
+
- Standardized package metadata across configuration files
|
|
32
|
+
- Cleaned up build artifacts and improved .gitignore
|
|
33
|
+
|
|
34
|
+
### Documentation
|
|
35
|
+
- Added CHANGELOG.md
|
|
36
|
+
- Added SECURITY.md
|
|
37
|
+
- Updated README.md with installation and usage examples
|
|
38
|
+
- Added proper Python package structure
|
|
39
|
+
|
|
40
|
+
### Deprecated
|
|
41
|
+
- `pydmc_route` package name (use `droute` instead)
|
|
42
|
+
- Backwards compatibility maintained through v0.x releases
|
|
43
|
+
- Will be removed in v1.0.0
|
|
44
|
+
|
|
45
|
+
## Previous Versions
|
|
46
|
+
|
|
47
|
+
Previous development versions (pre-0.5.0) were not released to PyPI.
|
|
48
|
+
|
|
49
|
+
[0.5.0]: https://github.com/DarriEy/dRoute/releases/tag/v0.5.0
|
|
@@ -0,0 +1,526 @@
|
|
|
1
|
+
cmake_minimum_required(VERSION 3.14)
|
|
2
|
+
project(dmc_route
|
|
3
|
+
VERSION 0.5.0
|
|
4
|
+
DESCRIPTION "Differentiable Muskingum-Cunge Routing"
|
|
5
|
+
LANGUAGES CXX
|
|
6
|
+
)
|
|
7
|
+
|
|
8
|
+
# ============ Options ============
|
|
9
|
+
option(DMC_ENABLE_AD "Enable automatic differentiation via CoDiPack" ON)
|
|
10
|
+
option(DMC_ENABLE_ENZYME "Enable Enzyme AD (requires Clang with Enzyme plugin)" OFF)
|
|
11
|
+
option(DMC_ENABLE_NETCDF "Enable NetCDF input support" ON)
|
|
12
|
+
option(DMC_BUILD_TESTS "Build unit tests" ON)
|
|
13
|
+
option(DMC_BUILD_PYTHON "Build Python bindings via pybind11" OFF)
|
|
14
|
+
option(DMC_BUILD_SHARED "Build shared library" ON)
|
|
15
|
+
|
|
16
|
+
# ============ C++ Standard ============
|
|
17
|
+
set(CMAKE_CXX_STANDARD 17)
|
|
18
|
+
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
|
19
|
+
set(CMAKE_CXX_EXTENSIONS OFF)
|
|
20
|
+
|
|
21
|
+
# ============ Dependencies via FetchContent ============
|
|
22
|
+
include(FetchContent)
|
|
23
|
+
|
|
24
|
+
# Use shallow clones to speed up downloads
|
|
25
|
+
set(FETCHCONTENT_QUIET OFF)
|
|
26
|
+
|
|
27
|
+
# CoDiPack (header-only AD library)
|
|
28
|
+
if(DMC_ENABLE_AD)
|
|
29
|
+
FetchContent_Declare(
|
|
30
|
+
codipack
|
|
31
|
+
GIT_REPOSITORY https://github.com/SciCompKL/CoDiPack.git
|
|
32
|
+
GIT_TAG v2.2.0
|
|
33
|
+
GIT_SHALLOW TRUE
|
|
34
|
+
)
|
|
35
|
+
FetchContent_MakeAvailable(codipack)
|
|
36
|
+
message(STATUS "CoDiPack enabled for automatic differentiation")
|
|
37
|
+
endif()
|
|
38
|
+
|
|
39
|
+
# Enzyme AD support
|
|
40
|
+
if(DMC_ENABLE_ENZYME)
|
|
41
|
+
# Enzyme is a compiler PLUGIN, not a linked library
|
|
42
|
+
# It transforms LLVM IR at compile time to generate derivatives
|
|
43
|
+
|
|
44
|
+
# Try to find Enzyme plugin
|
|
45
|
+
set(ENZYME_SEARCH_PATHS
|
|
46
|
+
"/opt/homebrew/lib"
|
|
47
|
+
"/opt/homebrew/Cellar/enzyme"
|
|
48
|
+
"/usr/local/lib"
|
|
49
|
+
"/usr/lib"
|
|
50
|
+
"${CMAKE_PREFIX_PATH}/lib"
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
# Find the ClangEnzyme plugin
|
|
54
|
+
find_file(ENZYME_PLUGIN
|
|
55
|
+
NAMES
|
|
56
|
+
ClangEnzyme-21.dylib
|
|
57
|
+
ClangEnzyme-20.dylib
|
|
58
|
+
ClangEnzyme-19.dylib
|
|
59
|
+
ClangEnzyme-18.dylib
|
|
60
|
+
ClangEnzyme-17.dylib
|
|
61
|
+
ClangEnzyme.dylib
|
|
62
|
+
LLDEnzyme-21.dylib
|
|
63
|
+
LLVMEnzyme-21.dylib
|
|
64
|
+
ClangEnzyme-21.so
|
|
65
|
+
ClangEnzyme-20.so
|
|
66
|
+
ClangEnzyme-19.so
|
|
67
|
+
ClangEnzyme.so
|
|
68
|
+
PATHS ${ENZYME_SEARCH_PATHS}
|
|
69
|
+
PATH_SUFFIXES enzyme
|
|
70
|
+
NO_DEFAULT_PATH
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
# Also try globbing for any version
|
|
74
|
+
if(NOT ENZYME_PLUGIN)
|
|
75
|
+
file(GLOB ENZYME_PLUGIN_GLOB
|
|
76
|
+
"/opt/homebrew/lib/ClangEnzyme*.dylib"
|
|
77
|
+
"/opt/homebrew/Cellar/enzyme/*/lib/ClangEnzyme*.dylib"
|
|
78
|
+
"/usr/lib/ClangEnzyme*.so"
|
|
79
|
+
"/usr/local/lib/ClangEnzyme*.so"
|
|
80
|
+
)
|
|
81
|
+
if(ENZYME_PLUGIN_GLOB)
|
|
82
|
+
list(GET ENZYME_PLUGIN_GLOB 0 ENZYME_PLUGIN)
|
|
83
|
+
endif()
|
|
84
|
+
endif()
|
|
85
|
+
|
|
86
|
+
if(ENZYME_PLUGIN)
|
|
87
|
+
message(STATUS "Found Enzyme plugin: ${ENZYME_PLUGIN}")
|
|
88
|
+
|
|
89
|
+
# Enzyme is used as a compiler plugin via -fplugin flag
|
|
90
|
+
set(ENZYME_COMPILE_FLAGS "-fplugin=${ENZYME_PLUGIN}")
|
|
91
|
+
set(DMC_ENZYME_AVAILABLE TRUE)
|
|
92
|
+
|
|
93
|
+
# Check if using Clang
|
|
94
|
+
if(NOT CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
|
95
|
+
message(WARNING "Enzyme requires Clang compiler. Current: ${CMAKE_CXX_COMPILER_ID}")
|
|
96
|
+
message(WARNING "Enzyme AD will be available but may not work correctly.")
|
|
97
|
+
endif()
|
|
98
|
+
|
|
99
|
+
else()
|
|
100
|
+
message(WARNING "")
|
|
101
|
+
message(WARNING "==========================================================")
|
|
102
|
+
message(WARNING "Enzyme plugin not found!")
|
|
103
|
+
message(WARNING "")
|
|
104
|
+
message(WARNING "Enzyme AD will be DISABLED.")
|
|
105
|
+
message(WARNING "")
|
|
106
|
+
message(WARNING "To enable Enzyme:")
|
|
107
|
+
message(WARNING " 1. Install Enzyme: brew install enzyme (macOS)")
|
|
108
|
+
message(WARNING " 2. Or build from source: https://enzyme.mit.edu")
|
|
109
|
+
message(WARNING " 3. Specify plugin path: -DENZYME_PLUGIN=/path/to/ClangEnzyme.so")
|
|
110
|
+
message(WARNING "==========================================================")
|
|
111
|
+
message(WARNING "")
|
|
112
|
+
set(DMC_ENABLE_ENZYME OFF)
|
|
113
|
+
set(DMC_ENZYME_AVAILABLE FALSE)
|
|
114
|
+
endif()
|
|
115
|
+
endif()
|
|
116
|
+
|
|
117
|
+
# OpenMP for parallel routing
|
|
118
|
+
option(DMC_ENABLE_OPENMP "Enable OpenMP parallelization" OFF)
|
|
119
|
+
if(DMC_ENABLE_OPENMP)
|
|
120
|
+
# On macOS with AppleClang, we need to help CMake find libomp from Homebrew
|
|
121
|
+
if(APPLE AND CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
|
122
|
+
execute_process(
|
|
123
|
+
COMMAND brew --prefix libomp
|
|
124
|
+
OUTPUT_VARIABLE HOMEBREW_LIBOMP_PREFIX
|
|
125
|
+
OUTPUT_STRIP_TRAILING_WHITESPACE
|
|
126
|
+
ERROR_QUIET
|
|
127
|
+
)
|
|
128
|
+
if(HOMEBREW_LIBOMP_PREFIX)
|
|
129
|
+
message(STATUS "Found Homebrew libomp at: ${HOMEBREW_LIBOMP_PREFIX}")
|
|
130
|
+
set(OpenMP_C_FLAGS "-Xpreprocessor -fopenmp -I${HOMEBREW_LIBOMP_PREFIX}/include")
|
|
131
|
+
set(OpenMP_CXX_FLAGS "-Xpreprocessor -fopenmp -I${HOMEBREW_LIBOMP_PREFIX}/include")
|
|
132
|
+
set(OpenMP_C_LIB_NAMES "omp")
|
|
133
|
+
set(OpenMP_CXX_LIB_NAMES "omp")
|
|
134
|
+
set(OpenMP_omp_LIBRARY "${HOMEBREW_LIBOMP_PREFIX}/lib/libomp.dylib")
|
|
135
|
+
else()
|
|
136
|
+
message(FATAL_ERROR "OpenMP requested but libomp not found. Install with: brew install libomp")
|
|
137
|
+
endif()
|
|
138
|
+
endif()
|
|
139
|
+
|
|
140
|
+
find_package(OpenMP REQUIRED)
|
|
141
|
+
message(STATUS "OpenMP enabled for parallel routing")
|
|
142
|
+
|
|
143
|
+
# CRITICAL: Enable thread-safe CoDiPack when using OpenMP
|
|
144
|
+
# CoDiPack v2.2+ uses thread-local tapes by default, but we add
|
|
145
|
+
# explicit defines for safety and compatibility
|
|
146
|
+
add_compile_definitions(CODI_EnableOpenMP)
|
|
147
|
+
endif()
|
|
148
|
+
|
|
149
|
+
# BMI C++ specification (header-only, just download it)
|
|
150
|
+
set(BMI_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/external/bmi")
|
|
151
|
+
if(NOT EXISTS "${BMI_INCLUDE_DIR}/bmi.hxx")
|
|
152
|
+
message(STATUS "Downloading BMI C++ header...")
|
|
153
|
+
file(MAKE_DIRECTORY ${BMI_INCLUDE_DIR})
|
|
154
|
+
file(DOWNLOAD
|
|
155
|
+
"https://raw.githubusercontent.com/csdms/bmi-cxx/master/bmi.hxx"
|
|
156
|
+
"${BMI_INCLUDE_DIR}/bmi.hxx"
|
|
157
|
+
STATUS download_status
|
|
158
|
+
)
|
|
159
|
+
list(GET download_status 0 status_code)
|
|
160
|
+
if(NOT status_code EQUAL 0)
|
|
161
|
+
message(FATAL_ERROR "Failed to download bmi.hxx")
|
|
162
|
+
endif()
|
|
163
|
+
endif()
|
|
164
|
+
|
|
165
|
+
# yaml-cpp for configuration - prefer system install
|
|
166
|
+
find_package(yaml-cpp QUIET)
|
|
167
|
+
if(NOT yaml-cpp_FOUND)
|
|
168
|
+
message(STATUS "yaml-cpp not found, will download (this may take a minute)...")
|
|
169
|
+
FetchContent_Declare(
|
|
170
|
+
yaml-cpp
|
|
171
|
+
GIT_REPOSITORY https://github.com/jbeder/yaml-cpp.git
|
|
172
|
+
GIT_TAG yaml-cpp-0.7.0
|
|
173
|
+
GIT_SHALLOW TRUE
|
|
174
|
+
)
|
|
175
|
+
set(YAML_CPP_BUILD_TESTS OFF CACHE BOOL "" FORCE)
|
|
176
|
+
set(YAML_CPP_BUILD_TOOLS OFF CACHE BOOL "" FORCE)
|
|
177
|
+
set(YAML_CPP_BUILD_CONTRIB OFF CACHE BOOL "" FORCE)
|
|
178
|
+
FetchContent_MakeAvailable(yaml-cpp)
|
|
179
|
+
endif()
|
|
180
|
+
|
|
181
|
+
# NetCDF for reading model outputs
|
|
182
|
+
if(DMC_ENABLE_NETCDF)
|
|
183
|
+
# Try to find system netCDF-cxx4
|
|
184
|
+
find_package(netCDFCxx QUIET)
|
|
185
|
+
if(NOT netCDFCxx_FOUND)
|
|
186
|
+
# Fall back to netCDF C library with our own C++ wrapper
|
|
187
|
+
find_package(netCDF QUIET)
|
|
188
|
+
if(netCDF_FOUND)
|
|
189
|
+
message(STATUS "Found netCDF C library, using thin C++ wrapper")
|
|
190
|
+
set(DMC_USE_NETCDF_C ON)
|
|
191
|
+
else()
|
|
192
|
+
message(WARNING "NetCDF not found. Install libnetcdf-dev and libnetcdf-c++4-dev, or disable with -DDMC_ENABLE_NETCDF=OFF")
|
|
193
|
+
set(DMC_ENABLE_NETCDF OFF)
|
|
194
|
+
endif()
|
|
195
|
+
else()
|
|
196
|
+
message(STATUS "Found netCDF-cxx4")
|
|
197
|
+
set(DMC_USE_NETCDF_CXX4 ON)
|
|
198
|
+
endif()
|
|
199
|
+
endif()
|
|
200
|
+
|
|
201
|
+
# nlohmann/json for GeoJSON parsing
|
|
202
|
+
FetchContent_Declare(
|
|
203
|
+
nlohmann_json
|
|
204
|
+
GIT_REPOSITORY https://github.com/nlohmann/json.git
|
|
205
|
+
GIT_TAG v3.11.3
|
|
206
|
+
GIT_SHALLOW TRUE
|
|
207
|
+
)
|
|
208
|
+
set(JSON_BuildTests OFF CACHE BOOL "" FORCE)
|
|
209
|
+
FetchContent_MakeAvailable(nlohmann_json)
|
|
210
|
+
|
|
211
|
+
# ============ Main Library ============
|
|
212
|
+
add_library(dmc_route INTERFACE)
|
|
213
|
+
|
|
214
|
+
target_include_directories(dmc_route INTERFACE
|
|
215
|
+
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
|
|
216
|
+
$<BUILD_INTERFACE:${BMI_INCLUDE_DIR}>
|
|
217
|
+
$<INSTALL_INTERFACE:include>
|
|
218
|
+
)
|
|
219
|
+
|
|
220
|
+
if(DMC_ENABLE_AD)
|
|
221
|
+
target_include_directories(dmc_route INTERFACE
|
|
222
|
+
${codipack_SOURCE_DIR}/include
|
|
223
|
+
)
|
|
224
|
+
target_compile_definitions(dmc_route INTERFACE DMC_USE_CODIPACK)
|
|
225
|
+
endif()
|
|
226
|
+
|
|
227
|
+
# Enzyme support
|
|
228
|
+
if(DMC_ENABLE_ENZYME AND DMC_ENZYME_AVAILABLE)
|
|
229
|
+
target_compile_definitions(dmc_route INTERFACE DMC_USE_ENZYME)
|
|
230
|
+
target_compile_options(dmc_route INTERFACE ${ENZYME_COMPILE_FLAGS})
|
|
231
|
+
message(STATUS "Enzyme AD enabled with plugin: ${ENZYME_PLUGIN}")
|
|
232
|
+
endif()
|
|
233
|
+
|
|
234
|
+
# NetCDF support
|
|
235
|
+
if(DMC_ENABLE_NETCDF)
|
|
236
|
+
target_compile_definitions(dmc_route INTERFACE DMC_USE_NETCDF)
|
|
237
|
+
if(DMC_USE_NETCDF_CXX4)
|
|
238
|
+
target_link_libraries(dmc_route INTERFACE netCDF::netcdf-cxx4)
|
|
239
|
+
target_compile_definitions(dmc_route INTERFACE DMC_USE_NETCDF_CXX4)
|
|
240
|
+
elseif(DMC_USE_NETCDF_C)
|
|
241
|
+
target_link_libraries(dmc_route INTERFACE netCDF::netcdf)
|
|
242
|
+
target_compile_definitions(dmc_route INTERFACE DMC_USE_NETCDF_C)
|
|
243
|
+
endif()
|
|
244
|
+
endif()
|
|
245
|
+
|
|
246
|
+
# JSON for GeoJSON parsing
|
|
247
|
+
target_link_libraries(dmc_route INTERFACE nlohmann_json::nlohmann_json)
|
|
248
|
+
|
|
249
|
+
# Homebrew LLVM on macOS ships its own libc++ that matches the compiler headers.
|
|
250
|
+
# When using that toolchain, prefer its lib directory to avoid std:: symbols missing at link.
|
|
251
|
+
set(DMC_LLVM_LIBDIR "")
|
|
252
|
+
if(APPLE)
|
|
253
|
+
if(DEFINED ENV{LLVM_PREFIX})
|
|
254
|
+
set(DMC_LLVM_LIBDIR "$ENV{LLVM_PREFIX}/lib")
|
|
255
|
+
else()
|
|
256
|
+
get_filename_component(_dmc_clang_bin "${CMAKE_CXX_COMPILER}" DIRECTORY)
|
|
257
|
+
get_filename_component(_dmc_llvm_prefix "${_dmc_clang_bin}" DIRECTORY)
|
|
258
|
+
if(EXISTS "${_dmc_llvm_prefix}/lib/libc++.dylib")
|
|
259
|
+
set(DMC_LLVM_LIBDIR "${_dmc_llvm_prefix}/lib")
|
|
260
|
+
endif()
|
|
261
|
+
endif()
|
|
262
|
+
endif()
|
|
263
|
+
set(DMC_LLVM_LIBCXX "")
|
|
264
|
+
set(DMC_LLVM_LIBCXXABI "")
|
|
265
|
+
if(DMC_LLVM_LIBDIR)
|
|
266
|
+
if(EXISTS "${DMC_LLVM_LIBDIR}/libc++.dylib")
|
|
267
|
+
set(DMC_LLVM_LIBCXX "${DMC_LLVM_LIBDIR}/libc++.dylib")
|
|
268
|
+
elseif(EXISTS "${DMC_LLVM_LIBDIR}/libc++.1.dylib")
|
|
269
|
+
set(DMC_LLVM_LIBCXX "${DMC_LLVM_LIBDIR}/libc++.1.dylib")
|
|
270
|
+
endif()
|
|
271
|
+
if(EXISTS "${DMC_LLVM_LIBDIR}/libc++abi.dylib")
|
|
272
|
+
set(DMC_LLVM_LIBCXXABI "${DMC_LLVM_LIBDIR}/libc++abi.dylib")
|
|
273
|
+
elseif(EXISTS "${DMC_LLVM_LIBDIR}/libc++abi.1.dylib")
|
|
274
|
+
set(DMC_LLVM_LIBCXXABI "${DMC_LLVM_LIBDIR}/libc++abi.1.dylib")
|
|
275
|
+
endif()
|
|
276
|
+
endif()
|
|
277
|
+
if(APPLE)
|
|
278
|
+
execute_process(
|
|
279
|
+
COMMAND ${CMAKE_CXX_COMPILER} -print-file-name=libc++.dylib
|
|
280
|
+
OUTPUT_VARIABLE _dmc_libcxx_path
|
|
281
|
+
OUTPUT_STRIP_TRAILING_WHITESPACE
|
|
282
|
+
)
|
|
283
|
+
if(_dmc_libcxx_path AND NOT _dmc_libcxx_path STREQUAL "libc++.dylib" AND EXISTS "${_dmc_libcxx_path}")
|
|
284
|
+
get_filename_component(DMC_LLVM_LIBDIR "${_dmc_libcxx_path}" DIRECTORY)
|
|
285
|
+
set(DMC_LLVM_LIBCXX "${_dmc_libcxx_path}")
|
|
286
|
+
endif()
|
|
287
|
+
execute_process(
|
|
288
|
+
COMMAND ${CMAKE_CXX_COMPILER} -print-file-name=libc++abi.dylib
|
|
289
|
+
OUTPUT_VARIABLE _dmc_libcxxabi_path
|
|
290
|
+
OUTPUT_STRIP_TRAILING_WHITESPACE
|
|
291
|
+
)
|
|
292
|
+
if(_dmc_libcxxabi_path AND NOT _dmc_libcxxabi_path STREQUAL "libc++abi.dylib" AND EXISTS "${_dmc_libcxxabi_path}")
|
|
293
|
+
set(DMC_LLVM_LIBCXXABI "${_dmc_libcxxabi_path}")
|
|
294
|
+
endif()
|
|
295
|
+
endif()
|
|
296
|
+
|
|
297
|
+
# ============ Shared Library Wrapper ============
|
|
298
|
+
if(DMC_BUILD_SHARED)
|
|
299
|
+
add_library(dmc_route_shared SHARED
|
|
300
|
+
src/lib.cpp
|
|
301
|
+
)
|
|
302
|
+
target_link_libraries(dmc_route_shared PUBLIC dmc_route)
|
|
303
|
+
set_target_properties(dmc_route_shared PROPERTIES
|
|
304
|
+
OUTPUT_NAME dmc_route
|
|
305
|
+
VERSION ${PROJECT_VERSION}
|
|
306
|
+
SOVERSION ${PROJECT_VERSION_MAJOR}
|
|
307
|
+
)
|
|
308
|
+
if(DMC_LLVM_LIBDIR)
|
|
309
|
+
target_link_directories(dmc_route_shared PRIVATE "${DMC_LLVM_LIBDIR}")
|
|
310
|
+
target_link_options(dmc_route_shared PRIVATE "-Wl,-rpath,${DMC_LLVM_LIBDIR}")
|
|
311
|
+
endif()
|
|
312
|
+
if(DMC_LLVM_LIBCXX)
|
|
313
|
+
target_link_libraries(dmc_route_shared PRIVATE "${DMC_LLVM_LIBCXX}")
|
|
314
|
+
endif()
|
|
315
|
+
if(DMC_LLVM_LIBCXXABI)
|
|
316
|
+
target_link_libraries(dmc_route_shared PRIVATE "${DMC_LLVM_LIBCXXABI}")
|
|
317
|
+
endif()
|
|
318
|
+
endif()
|
|
319
|
+
|
|
320
|
+
# ============ Python Bindings (pybind11) ============
|
|
321
|
+
option(DMC_BUILD_PYTHON "Build Python bindings" OFF)
|
|
322
|
+
if(DMC_BUILD_PYTHON)
|
|
323
|
+
# Find pybind11
|
|
324
|
+
find_package(pybind11 QUIET)
|
|
325
|
+
if(NOT pybind11_FOUND)
|
|
326
|
+
message(STATUS "pybind11 not found, fetching from GitHub...")
|
|
327
|
+
include(FetchContent)
|
|
328
|
+
FetchContent_Declare(
|
|
329
|
+
pybind11
|
|
330
|
+
GIT_REPOSITORY https://github.com/pybind/pybind11.git
|
|
331
|
+
GIT_TAG v2.11.1
|
|
332
|
+
)
|
|
333
|
+
FetchContent_MakeAvailable(pybind11)
|
|
334
|
+
endif()
|
|
335
|
+
|
|
336
|
+
message(STATUS "Building Python bindings")
|
|
337
|
+
|
|
338
|
+
# Read version from _version.py
|
|
339
|
+
file(READ "${CMAKE_SOURCE_DIR}/python/droute/_version.py" VERSION_FILE_CONTENTS)
|
|
340
|
+
string(REGEX MATCH "__version__ = \"([0-9]+\\.[0-9]+\\.[0-9]+)\"" _ ${VERSION_FILE_CONTENTS})
|
|
341
|
+
set(DMC_VERSION ${CMAKE_MATCH_1})
|
|
342
|
+
message(STATUS "dRoute version: ${DMC_VERSION}")
|
|
343
|
+
|
|
344
|
+
# Create the Python module
|
|
345
|
+
pybind11_add_module(_droute_core python/bindings.cpp)
|
|
346
|
+
target_link_libraries(_droute_core PRIVATE dmc_route)
|
|
347
|
+
target_compile_definitions(_droute_core PRIVATE DMC_VERSION="${DMC_VERSION}")
|
|
348
|
+
if(DMC_LLVM_LIBDIR)
|
|
349
|
+
target_link_directories(_droute_core PRIVATE "${DMC_LLVM_LIBDIR}")
|
|
350
|
+
target_link_options(_droute_core PRIVATE "-Wl,-rpath,${DMC_LLVM_LIBDIR}")
|
|
351
|
+
endif()
|
|
352
|
+
if(DMC_LLVM_LIBCXX)
|
|
353
|
+
target_link_libraries(_droute_core PRIVATE "${DMC_LLVM_LIBCXX}")
|
|
354
|
+
endif()
|
|
355
|
+
if(DMC_LLVM_LIBCXXABI)
|
|
356
|
+
target_link_libraries(_droute_core PRIVATE "${DMC_LLVM_LIBCXXABI}")
|
|
357
|
+
endif()
|
|
358
|
+
|
|
359
|
+
# Set output name and properties
|
|
360
|
+
if(DEFINED CMAKE_LIBRARY_OUTPUT_DIRECTORY)
|
|
361
|
+
set(_pydmc_route_output_dir "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}")
|
|
362
|
+
else()
|
|
363
|
+
set(_pydmc_route_output_dir "${CMAKE_BINARY_DIR}/python")
|
|
364
|
+
endif()
|
|
365
|
+
set_target_properties(_droute_core PROPERTIES
|
|
366
|
+
OUTPUT_NAME _droute_core
|
|
367
|
+
LIBRARY_OUTPUT_DIRECTORY "${_pydmc_route_output_dir}"
|
|
368
|
+
)
|
|
369
|
+
|
|
370
|
+
# Install Python module
|
|
371
|
+
if(DEFINED SKBUILD)
|
|
372
|
+
# If building with scikit-build, install to the package directory
|
|
373
|
+
install(TARGETS _droute_core DESTINATION .)
|
|
374
|
+
else()
|
|
375
|
+
# Otherwise install to lib/pythonX.Y/site-packages
|
|
376
|
+
install(TARGETS _droute_core
|
|
377
|
+
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/python${Python_VERSION_MAJOR}.${Python_VERSION_MINOR}/site-packages
|
|
378
|
+
)
|
|
379
|
+
endif()
|
|
380
|
+
|
|
381
|
+
message(STATUS "Python module will be built as: _droute_core")
|
|
382
|
+
endif()
|
|
383
|
+
|
|
384
|
+
if(DMC_ENABLE_ENZYME AND DMC_ENZYME_AVAILABLE AND DMC_BUILD_PYTHON AND TARGET _droute_core)
|
|
385
|
+
target_compile_definitions(_droute_core PRIVATE DMC_USE_ENZYME)
|
|
386
|
+
target_compile_options(_droute_core PRIVATE ${ENZYME_COMPILE_FLAGS})
|
|
387
|
+
endif()
|
|
388
|
+
|
|
389
|
+
# ============ Executable for Testing ============
|
|
390
|
+
option(DMC_BUILD_RUN "Build dmc_route_run CLI executable" ON)
|
|
391
|
+
if(DMC_BUILD_RUN)
|
|
392
|
+
add_executable(dmc_route_run src/main.cpp)
|
|
393
|
+
target_link_libraries(dmc_route_run PRIVATE dmc_route)
|
|
394
|
+
if(APPLE)
|
|
395
|
+
target_link_libraries(dmc_route_run PRIVATE c++)
|
|
396
|
+
endif()
|
|
397
|
+
if(DMC_LLVM_LIBDIR)
|
|
398
|
+
target_link_directories(dmc_route_run PRIVATE "${DMC_LLVM_LIBDIR}")
|
|
399
|
+
target_link_options(dmc_route_run PRIVATE "-Wl,-rpath,${DMC_LLVM_LIBDIR}")
|
|
400
|
+
endif()
|
|
401
|
+
if(DMC_LLVM_LIBCXX)
|
|
402
|
+
target_link_libraries(dmc_route_run PRIVATE "${DMC_LLVM_LIBCXX}")
|
|
403
|
+
endif()
|
|
404
|
+
if(DMC_LLVM_LIBCXXABI)
|
|
405
|
+
target_link_libraries(dmc_route_run PRIVATE "${DMC_LLVM_LIBCXXABI}")
|
|
406
|
+
endif()
|
|
407
|
+
endif()
|
|
408
|
+
|
|
409
|
+
# ============ Tests ============
|
|
410
|
+
if(DMC_BUILD_TESTS)
|
|
411
|
+
enable_testing()
|
|
412
|
+
|
|
413
|
+
# Gradient verification test
|
|
414
|
+
add_executable(test_gradients tests/test_gradients.cpp)
|
|
415
|
+
target_link_libraries(test_gradients PRIVATE dmc_route)
|
|
416
|
+
add_test(NAME gradient_verification COMMAND test_gradients)
|
|
417
|
+
|
|
418
|
+
# Single reach routing test
|
|
419
|
+
add_executable(test_single_reach tests/test_single_reach.cpp)
|
|
420
|
+
target_link_libraries(test_single_reach PRIVATE dmc_route)
|
|
421
|
+
add_test(NAME single_reach_routing COMMAND test_single_reach)
|
|
422
|
+
|
|
423
|
+
# BMI interface test
|
|
424
|
+
add_executable(test_bmi tests/test_bmi.cpp)
|
|
425
|
+
target_link_libraries(test_bmi PRIVATE dmc_route)
|
|
426
|
+
add_test(NAME bmi_interface COMMAND test_bmi)
|
|
427
|
+
|
|
428
|
+
# Rigorous gradient verification suite (AD vs Finite Differences)
|
|
429
|
+
add_executable(test_gradient_verification tests/test_gradient_verification.cpp)
|
|
430
|
+
target_link_libraries(test_gradient_verification PRIVATE dmc_route)
|
|
431
|
+
add_test(NAME gradient_verification_suite COMMAND test_gradient_verification)
|
|
432
|
+
|
|
433
|
+
# Comprehensive test suite
|
|
434
|
+
add_executable(test_comprehensive tests/test_comprehensive.cpp)
|
|
435
|
+
target_link_libraries(test_comprehensive PRIVATE dmc_route)
|
|
436
|
+
add_test(NAME comprehensive_suite COMMAND test_comprehensive)
|
|
437
|
+
|
|
438
|
+
# AD Backend Comparison test (CoDiPack vs Enzyme)
|
|
439
|
+
add_executable(test_ad_backend_comparison tests/test_ad_backend_comparison.cpp)
|
|
440
|
+
target_link_libraries(test_ad_backend_comparison PRIVATE dmc_route)
|
|
441
|
+
if(DMC_ENABLE_ENZYME AND DMC_ENZYME_AVAILABLE)
|
|
442
|
+
add_test(NAME ad_backend_comparison COMMAND test_ad_backend_comparison)
|
|
443
|
+
endif()
|
|
444
|
+
endif()
|
|
445
|
+
|
|
446
|
+
# OpenMP linking for parallel routing
|
|
447
|
+
if(DMC_ENABLE_OPENMP)
|
|
448
|
+
target_link_libraries(dmc_route INTERFACE OpenMP::OpenMP_CXX)
|
|
449
|
+
if(DMC_BUILD_RUN)
|
|
450
|
+
target_link_libraries(dmc_route_run PRIVATE OpenMP::OpenMP_CXX)
|
|
451
|
+
endif()
|
|
452
|
+
if(DMC_BUILD_TESTS)
|
|
453
|
+
target_link_libraries(test_comprehensive PRIVATE OpenMP::OpenMP_CXX)
|
|
454
|
+
target_link_libraries(test_ad_backend_comparison PRIVATE OpenMP::OpenMP_CXX)
|
|
455
|
+
endif()
|
|
456
|
+
endif()
|
|
457
|
+
|
|
458
|
+
# Enzyme compile options for test targets
|
|
459
|
+
if(DMC_ENABLE_ENZYME AND DMC_ENZYME_AVAILABLE AND DMC_BUILD_TESTS)
|
|
460
|
+
target_compile_options(test_ad_backend_comparison PRIVATE ${ENZYME_COMPILE_FLAGS})
|
|
461
|
+
endif()
|
|
462
|
+
|
|
463
|
+
# ============ Installation ============
|
|
464
|
+
include(GNUInstallDirs)
|
|
465
|
+
|
|
466
|
+
install(DIRECTORY include/dmc
|
|
467
|
+
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
|
|
468
|
+
)
|
|
469
|
+
|
|
470
|
+
if(DMC_BUILD_SHARED)
|
|
471
|
+
install(TARGETS dmc_route_shared
|
|
472
|
+
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
|
473
|
+
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
|
474
|
+
)
|
|
475
|
+
endif()
|
|
476
|
+
|
|
477
|
+
if(DMC_BUILD_RUN)
|
|
478
|
+
install(TARGETS dmc_route_run
|
|
479
|
+
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
|
480
|
+
)
|
|
481
|
+
endif()
|
|
482
|
+
|
|
483
|
+
# ============ Package Configuration ============
|
|
484
|
+
include(CMakePackageConfigHelpers)
|
|
485
|
+
|
|
486
|
+
write_basic_package_version_file(
|
|
487
|
+
"${CMAKE_CURRENT_BINARY_DIR}/dmc_routeConfigVersion.cmake"
|
|
488
|
+
VERSION ${PROJECT_VERSION}
|
|
489
|
+
COMPATIBILITY AnyNewerVersion
|
|
490
|
+
)
|
|
491
|
+
|
|
492
|
+
configure_package_config_file(
|
|
493
|
+
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/dmc_routeConfig.cmake.in"
|
|
494
|
+
"${CMAKE_CURRENT_BINARY_DIR}/dmc_routeConfig.cmake"
|
|
495
|
+
INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/dmc_route
|
|
496
|
+
)
|
|
497
|
+
|
|
498
|
+
install(FILES
|
|
499
|
+
"${CMAKE_CURRENT_BINARY_DIR}/dmc_routeConfig.cmake"
|
|
500
|
+
"${CMAKE_CURRENT_BINARY_DIR}/dmc_routeConfigVersion.cmake"
|
|
501
|
+
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/dmc_route
|
|
502
|
+
)
|
|
503
|
+
|
|
504
|
+
# SUNDIALS support for Saint-Venant solver
|
|
505
|
+
option(DMC_ENABLE_SUNDIALS "Enable SUNDIALS for SVE solver" OFF)
|
|
506
|
+
|
|
507
|
+
if(DMC_ENABLE_SUNDIALS)
|
|
508
|
+
if(DEFINED SUNDIALS_ROOT)
|
|
509
|
+
set(SUNDIALS_DIR "${SUNDIALS_ROOT}/lib/cmake/sundials")
|
|
510
|
+
endif()
|
|
511
|
+
|
|
512
|
+
find_package(SUNDIALS REQUIRED COMPONENTS cvodes nvecserial sunlinsoldense sunmatrixdense)
|
|
513
|
+
|
|
514
|
+
add_definitions(-DDMC_ENABLE_SUNDIALS)
|
|
515
|
+
|
|
516
|
+
if(DMC_BUILD_PYTHON AND TARGET _droute_core)
|
|
517
|
+
target_link_libraries(_droute_core PRIVATE
|
|
518
|
+
SUNDIALS::cvodes
|
|
519
|
+
SUNDIALS::nvecserial
|
|
520
|
+
SUNDIALS::sunlinsoldense
|
|
521
|
+
SUNDIALS::sunmatrixdense
|
|
522
|
+
)
|
|
523
|
+
endif()
|
|
524
|
+
|
|
525
|
+
message(STATUS "SUNDIALS enabled for Saint-Venant solver")
|
|
526
|
+
endif()
|
droute-0.5.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Darri Eythorsson
|
|
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.
|
droute-0.5.0/MANIFEST.in
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
include README.md
|
|
2
|
+
include LICENSE
|
|
3
|
+
include CHANGELOG.md
|
|
4
|
+
include SECURITY.md
|
|
5
|
+
include CMakeLists.txt
|
|
6
|
+
include setup.py
|
|
7
|
+
include pyproject.toml
|
|
8
|
+
recursive-include cmake *.cmake *.in
|
|
9
|
+
recursive-include include *.hpp *.h
|
|
10
|
+
recursive-include src *.cpp *.c
|
|
11
|
+
recursive-include python *.cpp *.py
|
|
12
|
+
recursive-include external *.hpp *.h
|
|
13
|
+
global-exclude *.pyc *.pyo *.o *.obj *.so *.dylib *.dll
|
|
14
|
+
global-exclude __pycache__
|
|
15
|
+
global-exclude *.egg-info
|