Skip to content

Compute CDR uptake curve#417

Merged
NoraLoose merged 19 commits into
CWorthy-ocean:mainfrom
NoraLoose:cdr-uptake
Sep 8, 2025
Merged

Compute CDR uptake curve#417
NoraLoose merged 19 commits into
CWorthy-ocean:mainfrom
NoraLoose:cdr-uptake

Conversation

@NoraLoose
Copy link
Copy Markdown
Collaborator

@NoraLoose NoraLoose commented Aug 19, 2025

This PR adds the method .cdr_metrics() to the ROMSOutput class. The method computes the required CDR diagnostics (if not already present), save them in the attribute .ds_cdr, and produce a plot of the uptake efficiency over time.

  • Closes Grid and features for analysis suite? #220
  • Tests added
  • Passes pre-commit run --all-files
  • Changes are documented in docs/releases.md
  • New functions/methods are listed in docs/api.rst
  • New functionality has documentation

@NoraLoose NoraLoose marked this pull request as draft August 19, 2025 23:05
@review-notebook-app
Copy link
Copy Markdown

Check out this pull request on  ReviewNB

See visual diffs & provide feedback on Jupyter Notebooks.


Powered by ReviewNB

@NoraLoose NoraLoose marked this pull request as ready for review August 26, 2025 16:18
Copy link
Copy Markdown
Contributor

@ScottEilerman ScottEilerman left a comment

Choose a reason for hiding this comment

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

A few optional suggestions/comments, mostly about small performance gains. Looks good!

dim=["eta_rho", "xi_rho"]
)
* ds_cdr["window_length"]
).cumsum(dim="time")
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Are the flux values 2-d arrays at the top layer, or are they 3-d (and presumably zero) for all the deeper layers? I assume the former, but if the latter, it'd be an efficiency gain to select s_rho=0 (or -1) somewhere in here, right?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

They are 2-d arrays and have no s_rho dimension.

)

# Normalize by cumulative source with safe division (NaN where source=0)
with np.errstate(divide="ignore", invalid="ignore"):
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I've never seen this errstate thing before. Interesting!

An alternative would be to formulate the below like uptake_efficiency_flux = np.where(source == 0, np.nan, flux / source). I suspect (but haven't tested) that it might be a little faster too. Error handling can be slow, so if the current code is actually triggering and then bypassing a lot of errors, it might be slower.

This assumes we're only concerned with zeros in source and not nans in source or flux. If that's the case, you can probably disregard.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

The point of np.errstate here was to suppress a bunch of annoying warnings that the user will see if we divide by zero. Maybe there is a better way to do this?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I thought that doing uptake_efficiency_flux = np.where(source == 0, np.nan, flux / source) would get rid of the warnings by not dividing by zero in the first place, but after thinking for an additional second and then also trying it in a terminal, it looks like it does still calculate the entirety of flux/source prior to subsetting/selecting, so nevermind. 🙃

Comment thread roms_tools/analysis/roms_output.py Outdated
# Pick the variable
field = self.ds[var_name]
# Pick the variable, prefer ds_cdr if it exists
field = ds_cdr[var_name] if ds_cdr and var_name in ds_cdr else self.ds[var_name]
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

In general, a preferable pattern to some of these "does it exist" checks would be to make ds_cdr a @property that gets lazily calculated the first time it's needed. That way a user or developer doesn't need to have pre-knowledge about its existence or worry about getattrs and Nones. It makes certain linters happier too.

Here, we'd have to think a little on this logic. Probably we'd want a list of possible variables in ds_cdr, so that we don't trigger the cdr analysis just to see if a var_name might be in there.

Consider this one optional. It'll work fine as-is, and the headache of maintaining var lists or worrying about when the computation might get triggered could outweigh the other considerations.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Oh! It turns out we don’t need to check for ds_cdr in the plot method after all. The only variables present in ds_cdr but not in ds are the uptake curves, which are plotted using a separate function, plot_uptake_efficiency, since plot doesn’t actually handle time series.

This check is just a leftover from an intermediate commit. I will remove it!

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Comment thread roms_tools/plot.py Outdated
times = ds["abs_time"]

# Check for monotonically increasing times
if not np.all(np.diff(times) > np.timedelta64(0, "s")):
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Probably insignificant, but there's a slight efficiency gain to be had -- see the last code block here.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

@NoraLoose
Copy link
Copy Markdown
Collaborator Author

I think this is good to merge, @ScottEilerman?

@ScottEilerman
Copy link
Copy Markdown
Contributor

Yep go for it!

@NoraLoose NoraLoose merged commit 2767c49 into CWorthy-ocean:main Sep 8, 2025
12 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.

Grid and features for analysis suite?

2 participants