Skip to content

How should we ensure that the source state for each water tracer is set correctly? #511

@billsacks

Description

@billsacks

How should we ensure that the source state for each water tracer is set correctly?

The water tracer consistency check will be very helpful in catching certain problems with water tracers / isotopes as the code evolves over time. Specifically, it can catch the situation when a new flux is added but isn't updated at all. However, I realized that one (probably common) bug that it can't catch is: If we use the current ratio in state variable X to set a given tracer flux based on the bulk flux, but in fact this flux comes from state variable Y. This type of bug could be introduced as we first write the tracer-handling code (or when a new flux variable is added to the model), or it could be introduced later – for example, if a new state variable is introduced and now a certain flux originates from that new state variable, but the person making this change forgot to update the tracer-handling code accordingly. The water tracer consistency test would still pass in this case: since all state variables have the same tracer ratio in this test, the test can't catch problems with specifying the wrong source state.

Off-hand, I can think of three ways to reduce the likelihood of this bug (along with a 0th, do-nothing solution):

  1. Do nothing about this. We may decide that all of the possible solutions are either infeasible or add too much complexity, and so we should just accept the risk that bugs of this variety will be introduced in the the tracer-handling code in order to keep code complexity lower (since this complexity would likely apply to the bulk as well as to the tracer code, and so would affect all scientists working with the code).

  2. For each flux variable in the model, introduce a corresponding pointer that points to the source state variable for that flux. These pointers would be set up in initialization (e.g., in initialization, we would set bar_flux_source_state => waterstate_inst%foo_state). These pointers would then be used in two places:

    (a) To pull the flux out of the source state: code like foo_state = foo_state - bar_flux*dt would be replaced by bar_flux_source_state = bar_flux_source_state - bar_flux*dt

    (b) To set the source state for the tracer flux updates

    Arguments for this are:

    • I really like the confidence that this would give me that (a) and (b) remain in sync.

    • We might want something like this eventually anyway, to facilitate separating the physics from the numerics. I'd like to hear thoughts from @martynpclark or others on how we will might eventually want the code to look for other purposes in terms of encoding the connection between a flux variable and its source (and possibly destination) state variable.

    Arguments against this are:

    • I'm a bit concerned that the change in (a) would increase the learning curve for understanding the code.

    • Some flux variables may not lend themselves to this uniform treatment – i.e., that each flux has a single source. This could particularly be true if a flux variable pulls from source X in some cases and source Y in other cases. However, there are probably benefits from reworking the code so that those are two different flux variables anyway.

  3. Put code for tracer updates near the code for removal of a flux from a state. i.e., the code to update the foo_flux tracer flux would be right next to the code for removing foo_flux from its source state. This wouldn't be as robust as (1), but should make it more likely that someone changing the source state for a flux would also remember to update the tracer-update code. Downsides are that this might not be how we'd ideally want to organize the code, and this won't be as clean when there are multiple fluxes drawing from the same state.

  4. Add a system test that checks this somehow – similar to the existing tracer consistency test, but somehow ensuring that we have the right source state for each flux. I haven't been able to think of a way this could be done, but @davidnoone or someone else has some ideas here?

I'm not sure what's best at this point. I don't really like relying on (2). If there's a way to do (3) (and especially if it can be done without introducing too much complexity into the code), that might be ideal. Otherwise, (1) seems like it could be a good option, but I'd like to hear thoughts from others about whether the benefits outweigh the extra complexity.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    Status

    Done

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions