Optimize GridInterp tensor-product cubic interpolation - #3413
Merged
Conversation
Speed up the 3D/4D grid interpolation routines in the NWTC Library while preserving the public interface and functionality. Results are numerically equivalent, differing only at floating-point truncation level from a strictly serial evaluation. Changes: - Setup routines (3D/4D/N): build the weight tensors with array syntax over the contiguous first dimension so the inner writes vectorize, and hoist shared subexpressions (e.g. Nkl = N1D(k,3)*N1D(l,4)). - Scalar and vector interpolation routines: accumulate over the innermost dimension into four independent partial sums to break the serial add dependency chain (latency hiding) and expose ILP, then combine at the end. Index lookups are hoisted out of the inner loop. - Vector routines: move the component (vi) loop outermost for unit-stride access and per-component accumulation. - Slope routines (N/S): accumulate both derivatives with dual accumulators and reuse a single data load per grid point instead of loading the same value twice. Validation: all 10 SeaState regression tests pass, and the HydroDyn WAMIT interpolation paths (including hd_NBodyMod1) pass. gfortran does not reassociate reduction sums by default, so the multi-accumulator regrouping is the primary win. Co-authored-by: GitHub Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Claude Opus <claude@anthropic.com>
Contributor
There was a problem hiding this comment.
Pull request overview
This PR optimizes the NWTC Library GridInterp tensor-product cubic interpolation implementation to improve runtime performance while keeping the public API unchanged, primarily by increasing vectorization opportunities and reducing reduction-chain latency in inner loops.
Changes:
- Rewrites 3D/4D/N setup routines to build weight tensors using whole-slice array syntax and hoisted shared subexpressions.
- Refactors scalar and vector interpolation kernels to use multiple accumulators and hoist index lookups out of inner loops.
- Refactors slope (S/N) routines to reuse a single grid-point load for both derivative accumulations.
Suppressed comments (3)
modules/nwtc-library/src/GridInterp.f90:411
- In
GridInterpSetupN, the local variableiis declared but no longer used after replacing theiloop with whole-slice assignments intom%N4D. Dropping it will avoid unused-variable warnings.
! Need two sets of weights for d(.)/dx and d(.)/dy. Borrow m%N4D for this.
do k = 1,4
do j = 1,4
m%N4D(:,j,k,1) = N1D(:,1) * (N1Ddx(j,2)*N1D (k,3))
m%N4D(:,j,k,2) = N1D(:,1) * (N1D (j,2)*N1Ddx(k,3))
modules/nwtc-library/src/GridInterp.f90:841
GridInterp4DVecNR8no longer initializes the result array before theviloop. IfvDimis 0, the loop won't run and the function result is undefined, whereas the previous implementation defined it to 0.0 via whole-array initialization.
! interpolate
do vi = 1,vDim
acc = 0.0_DbKi
modules/nwtc-library/src/GridInterp.f90:365
iis declared inGridInterpSetup4Dbut no longer used after converting the inneriloop to an array slice assignment. Removing it avoids unused-variable warnings.
do k = 1,4
Nkl = N1D(k,3)*N1D(l,4)
do j = 1,4
m%N4D(:,j,k,l) = N1D(:,1) * (N1D(j,2)*Nkl)
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
andrew-platt
approved these changes
Jul 31, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Feature or improvement description
Optimizes the tensor-product cubic interpolation routines in the NWTC Library's
GridInterpmodule for improved runtime performance, while preserving the public interface and functionality. The results are numerically equivalent to the original — differences arise only at floating-point truncation level due to summation regrouping, not from any change in the interpolation math.Key optimizations:
Nkl = N1D(k,3)*N1D(l,4)).Rationale:
gfortrandoes not reassociate reduction sums by default, so the original serial add chain was latency-bound. The multi-accumulator regrouping is the primary win.Related issue, if one exists
N/A
Impacted areas of the software
GridInterp.f90(only file changed)Downstream consumers exercised: SeaState (
SeaSt_WaveField) and HydroDyn/WAMIT (WAMIT_Interp)Additional supporting information
The amortization design of the setup routines (precomputing full weight tensors reused across many field interpolations at the same position) was preserved intentionally. No interface, argument, or return-type changes; the diff is 202 insertions / 112 deletions in a single file.
Generative AI usage
The optimization was developed with AI assistance (analysis, refactoring, and validation).
Co-authored-by: Microsoft Copilot [copilot@microsoft.com]
Co-authored-by: Anthropic Claude [claude@anthropic.com]
Test results, if applicable
No change to existing r-test expected, pending regression test completion.