Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

D8 routing #1633

Merged
merged 35 commits into from
Jan 24, 2025
Merged

D8 routing #1633

merged 35 commits into from
Jan 24, 2025

Conversation

emlys
Copy link
Member

@emlys emlys commented Sep 25, 2024

Description

This PR implements D8 equivalents of the routing functions that previously only supported MFD.
A "routing algorithm" option input (MFD or D8) is added to each model. Based on that option, the appropriate pygeoprocessing routing functions are called. For the model-specific routing functions, I used C++ templates to implement switching between MFD and D8 "modes" on the iterator classes in ManagedRaster.h. To make it possible to call the templated functions, I rewrote the bulk of the SDR, NDR, and SWY routing functions from Cython to C++. I'm happy to discuss pros and cons of this.

Future work: add logging to python from C++ extensions, add templating for ManagedRaster to read and return values of different data types

Checklist

  • Updated HISTORY.rst and link to any relevant issue (if these changes are user-facing)
  • Updated the user's guide (if needed)
  • Tested the Workbench UI (if relevant)

@emlys emlys changed the base branch from main to feature/routing-refactor September 25, 2024 20:10
@@ -337,15 +340,15 @@ class ManagedRaster {
}
};

template<class T>
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a class template. ManagedFlowDirRaster is not a class, but ManagedFlowDirRasater<MFD> and ManagedFlowDirRasater<D8> are classes that can be created from this template.

ManagedFlowDirRaster() {}

ManagedFlowDirRaster(char* raster_path, int band_id, bool write_mode)
: ManagedRaster(raster_path, band_id, write_mode) {}

template<typename T_ = T, std::enable_if_t<std::is_same<T_, MFD>::value>* = nullptr>
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This tells the compiler to use this implementation of is_local_high_point if the template argument is MFD. The same pattern is used in all the iterator classes below.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting! So then if we were to extend these classes to accommodate some additional routing method, we would need to add new classmethods that have a conditional like this?

@emlys emlys requested a review from phargogh January 9, 2025 23:12
@emlys emlys self-assigned this Jan 9, 2025
@emlys emlys marked this pull request as ready for review January 9, 2025 23:12
Copy link
Member

@phargogh phargogh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I really don't have anything to suggest at this time ... the solution's architecture makes sense to me given the constraints of a compiled language, I'm not seeing any compiler warnings, tests pass, and the outputs all make sense to me, as do the tests. This looks great!

ManagedFlowDirRaster() {}

ManagedFlowDirRaster(char* raster_path, int band_id, bool write_mode)
: ManagedRaster(raster_path, band_id, write_mode) {}

template<typename T_ = T, std::enable_if_t<std::is_same<T_, MFD>::value>* = nullptr>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting! So then if we were to extend these classes to accommodate some additional routing method, we would need to add new classmethods that have a conditional like this?

Comment on lines +90 to +93
if algorithm == 'MFD':
run_effective_retention[MFD](*args)
else: # D8
run_effective_retention[D8](*args)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I get it now! That is really pretty neat. So the implication is that the compiler is, effectively, rendering MFD and D8 versions of the underlying functions to allow us to call either one at runtime. Awesome.

@phargogh phargogh merged commit 756a4d0 into natcap:feature/routing-refactor Jan 24, 2025
29 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants