climt icon indicating copy to clipboard operation
climt copied to clipboard

The ability to use different state values in different modules

Open HaynesStephens opened this issue 5 years ago • 5 comments

  • CliMT version: 0.16.3
  • Python version: 3.6.5
  • Operating System: OSx

Description

Per Joy's request: I am trying to run a one-dimensional model that holds fixed the radiative properties of atmospheric water vapor. I've hacked a way to do it by creating two separate Adams-Bashforth tendency steppers, one for the radiative modules and one for the rest. In the radiative stepper, I prescribe a constant humidity profile at every step, whereas for the other stepper I allow the humidity to evolve. But if there were some wrapper or another method of being able to do this that were as easy as "humidity.rad=constant", that would help expand the innate capabilities of CliMT.

What I Did

time_stepper_phys = AdamsBashforth([slab, moist_convection])
time_stepper_rad = AdamsBashforth([radiation_lw, radiation_sw])

# Day length to match Shanshan
run_days = 10950
run_length = int((run_days * 24 * 60) / dt_minutes)

for i in range(run_length):
    rad_state_fixed_q = copy.deepcopy(state)
    phys_unfixed_q = rad_state_fixed_q['specific_humidity'].values[:].copy()
    rad_state_fixed_q['specific_humidity'].values[:] = control_q.copy()
    diagnostics, state = time_stepper_rad(rad_state_fixed_q, timestep)
    state['specific_humidity'].values[:] = phys_unfixed_q.copy()

    state.update(diagnostics)

HaynesStephens avatar Oct 30 '19 14:10 HaynesStephens

You could do this by creating a FixedInputWrapper which wraps a component and sets pre-specified inputs to constant value. It would look something like (untested):

class FixedInputWrapper(object):

    def __init__(self, wrapped_component, fixed_state):
        self._component = wrapped_component
        self._fixed_state = fixed_state

    @property
    def input_properties(self):
        return_dict = {}
        for name, properties in self._component.input_properties:
            if name not in self._fixed_state:
                return_dict[name] = properties
        return return_dict

    def __getattr__(self, item):
        return getattr(self._component, item)

    def __call__(self, state, *args, **kwargs):
        state.update(self._fixed_state)
        return self._component(state, *args, **kwargs)

You would use it like:

fixed_state = {
    'specific_humidity': initial_state['specific_humidity'],
}
radiation = FixedInputWrapper(RRTM(), fixed_state)
radiation_stepper = AdamsBashforth(radiation)

After that, you could use the radiation_stepper as normal, and it will always use the fixed array as input.

Note that you really want to just fix the humidity as input for the TendencyComponent and not for the Stepper, because otherwise the stepper will output the fixed humidity as the humidity for the next time step. Doing it with a wrapper on a TendencyComponent like above will make it so the radiative heating is computed with fixed humidity, but the humidity in the prognostic state will not be over-written.

It would be more appropriate to contribute this wrapper upstream into Sympl than into CliMT, but it's also fine to just have as an external example wrapper a user can put into their code.

mcgibbon avatar Oct 30 '19 18:10 mcgibbon

Yes, this should find its way to sympl eventually.

JoyMonteiro avatar Nov 01 '19 11:11 JoyMonteiro

Thank you @mcgibbon , that sounds very helpful.

Do you or @JoyMonteiro think that there could be a problem with how I structured my code to try and get the desired effect?

Just as a check, I can try the TendencyComponent approach and see if the results are any different than my script.

HaynesStephens avatar Nov 04 '19 19:11 HaynesStephens

I have been thinking about this, and there will be a difference if you use two timesteppers instead of a wrapper like @mcgibbon suggested.

This is because the input state to the second timestepper is the output of the first one. Thus, some components see a different model state than the convection scheme.

I don't think this should be a huge issue, however. You should verify that the model output seems scientifically sensible.

JoyMonteiro avatar Nov 08 '19 04:11 JoyMonteiro

Thanks, Joy. I'll give both runs a try and see if any differences result. Hope your paper worries are over or near-over for the time being!

I would love to talk with you sometime soon about the code, just so I can get a firm understanding on everything we've discussed. Let me know if you're available.

Best wishes, Haynes

On Thu, Nov 7, 2019 at 10:21 PM JoyMonteiro [email protected] wrote:

I have been thinking about this, and there will be a difference if you use two timesteppers instead of a wrapper like @mcgibbon https://github.com/mcgibbon suggested.

This is because the input state to the second timestepper is the output of the first one. Thus, some components see a different model state than the convection scheme.

I don't think this should be a huge issue, however. You should verify that the model output seems scientifically sensible.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/CliMT/climt/issues/115?email_source=notifications&email_token=AEOYOYGNTMXQRTZ76BKSSCDQSTSMVA5CNFSM4JG2EWR2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEDOV3FQ#issuecomment-551378326, or unsubscribe https://github.com/notifications/unsubscribe-auth/AEOYOYFLU75TQEEGDSCGZ53QSTSMVANCNFSM4JG2EWRQ .

HaynesStephens avatar Nov 11 '19 17:11 HaynesStephens