-
Notifications
You must be signed in to change notification settings - Fork 19
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
Use ClimaDiagnostics #2866
Use ClimaDiagnostics #2866
Conversation
512a258
to
9e48c9b
Compare
5ecaefc
to
0ca5847
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Before continuing with this PR, I insist that we fuse our diagnostic callbacks, so that we ensure that there is a path to something performant, before shipping this code off to ClimaDiagnostics. I raised this issue when this code was first added, and moving it to a separate repository will only make this problem more difficult to fix.
One of the reasons to move to a separate repo is to allow us to more easily update it. As you can see by the diff, everything is now encapsulated in ClimaDiagnostics and we can change how things are done without touching ClimaAtmos. ClimaDiagnostics already has a full integration test that runs in 20 seconds, greatly speeding up the pace of developlment. If we need optimization work, it will be faster to do it there. Also, ClimaLand and ClimaCoupler are going to use ClimaDiagnostics soon. They will probably have slightly different needs that will require some additional work in ClimaDiagnostics. I think that it is more important to bring the code to the end user sooner and figure out what needs to be done to support their needs instead of adding additional complexity to improve performance. |
If you'd prefer to fuse the callbacks in ClimaDiagnostics first, that's fine, but do that first. I don't want multiple repositories depending on a design pattern that does not scale. Fusing the callbacks changes the interface and the way it's called, so it's a breaking change. |
cfab722
to
0ca24ab
Compare
Sounds good. Can you define what you mean with fusing callbacks exactly?
With ClimaDiagnostics, the interface is one line |
Yes, all broadcast expressions need to be in the same function scope, and we can't have function calls between them. So, for example, one of these two forms would suffice: foreach(input_output_pairs) do out, args
out .= compute_diagnostics.(args, more_args...)
end
foreach(keys(diagnostics)) do key
out[key] .= compute_diagnostics.(diagnostics[key], args...)
end Basically, we need to be able to use the
Why would diagnostics have anything to do with the integrator? Re-creating the integrator violates the DRY principle-- we should probably make the integrator once, and I would prefer that happens in ClimaAtmos. I think ClimaDiagnostics should basically provide an interface for specifying a diagnostics callback. Using a |
Let's chat offline on how to accomplish this.
|
Sounds good.
Sounds good, I think ensuring that everything else is initialized before constructing the callback is not a problem.
I don't think that that logic should be in ClimaDiagnostics.
That's fine with me.
I personally like the idea of having some sort of initialization function, or at least some way to compile the diagnostics. |
73f64e8
to
8c9d4b6
Compare
7c58647
to
3f5daf6
Compare
return x | ||
end | ||
end | ||
error("Callback not found in $(affect!)") | ||
return nothing |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we remove this error? It might otherwise lead to confusing errors?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good question.
The function forced all the callbacks to be either AtmosCallbacks
or a specific type of DiffEqCallbacks
callback (one with the SavedValues
property), then the function atmos_callbacks
filtered different types of callbacks dropping the DiffEqCallbacks
callbacks. I flipped the conditional around so that atmos_callbacks
filters for AtmosCallbacks
(which is really the intent here: we want AtmosCallbacks
so that downstream functions can compute lcm and cycle). Therefore, there is no longer a reason to reject callbacks that are not AtmosCallbacks
or DiffEqCallbacks
.
The diagnostic callback is a SciMLBase.DiscreteCallback
, hence, it was hitting the error banch here. Note that there is no reason for the diagnostic callback to be an AtmosCallback as it doesn't have a strong notion of periodicity (e.g., calendar months have different number of timesteps).
ClimaAtmos.jl/src/callbacks/callback_helpers.jl
Lines 58 to 75 in 719ee49
callback_from_affect(x::AtmosCallback) = x | |
function callback_from_affect(affect!) | |
for p in propertynames(affect!) | |
x = getproperty(affect!, p) | |
if x isa AtmosCallback | |
return x | |
elseif x isa DECB.SavedValues | |
return x | |
end | |
end | |
error("Callback not found in $(affect!)") | |
end | |
function atmos_callbacks(cbs::SciMLBase.CallbackSet) | |
all_cbs = [cbs.continuous_callbacks..., cbs.discrete_callbacks...] | |
callback_objs = map(cb -> callback_from_affect(cb.affect!), all_cbs) | |
filter!(x -> !(x isa DECB.SavedValues), callback_objs) | |
return callback_objs | |
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks great, thank you!
3f5daf6
to
d3be8a3
Compare
This PR moves the logic underlying the diagnostic module to a separate package, ClimaDiagnostics.jl. In the processes, everything was documented and tests were added.
The reason for this change is twofold:
Diagnostics
ClimaDiagnostics
are more flexible: they are no longer tied to a specific number of iteration and can be triggered with any conditions (e.g., output a variable it is NaN). In the current form, they also allocate x15 times as much.Closes: #2623, #2598, #2837
Closes #2910