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.
Files changed (39) hide show
  1. droute-0.5.0/CHANGELOG.md +49 -0
  2. droute-0.5.0/CMakeLists.txt +526 -0
  3. droute-0.5.0/LICENSE +21 -0
  4. droute-0.5.0/MANIFEST.in +15 -0
  5. droute-0.5.0/PKG-INFO +213 -0
  6. droute-0.5.0/README.md +153 -0
  7. droute-0.5.0/SECURITY.md +72 -0
  8. droute-0.5.0/cmake/dmc_routeConfig.cmake.in +8 -0
  9. droute-0.5.0/include/dmc/ad_backend.hpp +183 -0
  10. droute-0.5.0/include/dmc/advanced_routing.hpp +1341 -0
  11. droute-0.5.0/include/dmc/bmi.hpp +479 -0
  12. droute-0.5.0/include/dmc/channel_geometry.hpp +393 -0
  13. droute-0.5.0/include/dmc/kernels_enzyme.hpp +2001 -0
  14. droute-0.5.0/include/dmc/network.hpp +319 -0
  15. droute-0.5.0/include/dmc/network_io.hpp +389 -0
  16. droute-0.5.0/include/dmc/parallel_routing.hpp +377 -0
  17. droute-0.5.0/include/dmc/router.hpp +2529 -0
  18. droute-0.5.0/include/dmc/runoff_forcing.hpp +626 -0
  19. droute-0.5.0/include/dmc/saint_venant_enzyme.hpp +1067 -0
  20. droute-0.5.0/include/dmc/saint_venant_router.hpp +834 -0
  21. droute-0.5.0/include/dmc/topology_nc.hpp +479 -0
  22. droute-0.5.0/include/dmc/types.hpp +197 -0
  23. droute-0.5.0/include/dmc/unified_router.hpp +855 -0
  24. droute-0.5.0/pyproject.toml +79 -0
  25. droute-0.5.0/python/bindings.cpp +1522 -0
  26. droute-0.5.0/python/droute/__init__.py +28 -0
  27. droute-0.5.0/python/droute/_version.py +3 -0
  28. droute-0.5.0/python/droute.egg-info/PKG-INFO +213 -0
  29. droute-0.5.0/python/droute.egg-info/SOURCES.txt +37 -0
  30. droute-0.5.0/python/droute.egg-info/dependency_links.txt +1 -0
  31. droute-0.5.0/python/droute.egg-info/not-zip-safe +1 -0
  32. droute-0.5.0/python/droute.egg-info/requires.txt +10 -0
  33. droute-0.5.0/python/droute.egg-info/top_level.txt +3 -0
  34. droute-0.5.0/python/pydmc_route.py +37 -0
  35. droute-0.5.0/python/test_routing_with_data.py +1360 -0
  36. droute-0.5.0/setup.cfg +4 -0
  37. droute-0.5.0/setup.py +83 -0
  38. droute-0.5.0/src/lib.cpp +41 -0
  39. 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.
@@ -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