Skip to content
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

The ability to use different state values in different modules #115

Open
HaynesStephens opened this issue Oct 30, 2019 · 5 comments
Open

Comments

@HaynesStephens
Copy link

  • 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)
@mcgibbon
Copy link
Member

mcgibbon commented Oct 30, 2019

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.

@JoyMonteiro
Copy link
Member

Yes, this should find its way to sympl eventually.

@HaynesStephens
Copy link
Author

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.

@JoyMonteiro
Copy link
Member

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.

@HaynesStephens
Copy link
Author

HaynesStephens commented Nov 11, 2019 via email

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

No branches or pull requests

3 participants