Skip to content

Commit

Permalink
Merge pull request atmtools#225 from lkluft/add-deepcopy
Browse files Browse the repository at this point in the history
Add deepcopy
  • Loading branch information
lkluft authored Jul 4, 2024
2 parents 43900e4 + 8875f34 commit bd11e2a
Show file tree
Hide file tree
Showing 15 changed files with 61 additions and 49 deletions.
2 changes: 1 addition & 1 deletion howto/atmosphere.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ Finally, we can plot the equilibrated temperature profile

```{code-cell} ipython3
fig, ax = plt.subplots()
plots.profile_p_log(atmosphere['plev'], atmosphere['T'][-1, :])
plots.profile_p_log(rce.atmosphere['plev'], rce.atmosphere['T'][-1, :])
ax.set_xlabel(r"$T$ / K")
ax.set_ylabel("$p$ / hPa")
```
12 changes: 6 additions & 6 deletions howto/clouds.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,12 @@ rce = konrad.RCE(
rce.run()
fig, (ax0, ax1) = plt.subplots(ncols=2, sharey=True)
plots.profile_p_log(atmosphere["plev"], atmosphere["T"][-1], ax=ax0)
plots.profile_p_log(rce.atmosphere["plev"], rce.atmosphere["T"][-1], ax=ax0)
ax0.set_ylabel("$p$ / hPa")
ax0.set_xlabel("$T$ / K")
ax1.axvline(0, color="k", linewidth=0.8)
plots.profile_p_log(atmosphere["plev"], rce.radiation["net_htngrt"][-1], ax=ax1)
plots.profile_p_log(rce.atmosphere["plev"], rce.radiation["net_htngrt"][-1], ax=ax1)
ax1.set_xlabel("Q / $\sf K\,day^{-1}$")
ax1.set_xlim(-4, 0.5)
ax1.set_ylim(bottom=phlev.max())
Expand All @@ -58,7 +58,7 @@ ax1.set_ylim(bottom=phlev.max())

```{code-cell} ipython3
single_cloud = konrad.cloud.ConceptualCloud(
atmosphere, # required for consistent coordinates
rce.atmosphere, # required for consistent coordinates
cloud_top=200e2, # in Pa
depth=100e2, # in Pa
phase="ice", # "ice" or "liquid"
Expand All @@ -68,20 +68,20 @@ single_cloud = konrad.cloud.ConceptualCloud(
rrtmg = konrad.radiation.RRTMG()
rrtmg.update_heatingrates(
atmosphere=atmosphere,
atmosphere=rce.atmosphere,
cloud=single_cloud,
)
fig, (ax0, ax1) = plt.subplots(ncols=2, sharey=True)
ax0.axvline(0, color="k", linewidth=0.8)
plots.profile_p_log(atmosphere["plev"], rrtmg["net_htngrt"][-1], ax=ax0)
plots.profile_p_log(rce.atmosphere["plev"], rrtmg["net_htngrt"][-1], ax=ax0)
ax0.set_xlabel("Q / $\sf K\,day^{-1}$")
ax0.set_xlim(-4, 0.5)
ax0.set_ylabel("$p$ / hPa")
ax0.set_ylim(bottom=phlev.max())
ax1.axvline(0, color="k", linewidth=0.8)
plots.profile_p_log(atmosphere["plev"], rrtmg["net_htngrt"][-1] - rrtmg["net_htngrt_clr"][-1], ax=ax1)
plots.profile_p_log(rce.atmosphere["plev"], rrtmg["net_htngrt"][-1] - rrtmg["net_htngrt_clr"][-1], ax=ax1)
ax1.set_xlabel("$\sf Q_\mathrm{cloud}$ / $\sf K\,day^{-1}$")
ax1.set_xlim(-2.25, 2.25)
ax1.set_ylim(bottom=phlev.max())
Expand Down
2 changes: 1 addition & 1 deletion howto/convection.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ In a second step, we enable the convective adjustment. We copy the existing atmo

```{code-cell} ipython3
rce = konrad.RCE(
atmosphere.copy(), # Create an separate atmosphere component.
atmosphere,
convection=konrad.convection.HardAdjustment(),
timestep='24h',
max_duration='150d',
Expand Down
4 changes: 2 additions & 2 deletions howto/feedback.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,10 @@ spinup = konrad.RCE(
)
spinup.run() # Start the simulation.
atmosphere["CO2"][:] *= 2.0 # double the CO2 concentration
spinup.atmosphere["CO2"][:] *= 2.0 # double the CO2 concentration
perturbed = konrad.RCE(
atmosphere,
spinup.atmosphere,
surface=konrad.surface.SlabOcean(
temperature=295.0,
heat_sink=spinup.radiation["toa"][-1],
Expand Down
6 changes: 3 additions & 3 deletions howto/forcing.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@ atmospheric state, especially the temperature, occur.

```{code-cell} ipython3
# Calculate OLR at perturbed atmospheric state.
atmosphere["CO2"][:] *= 2 # double the CO2 concentration
spinup.radiation.update_heatingrates(atmosphere)
spinup.atmosphere["CO2"][:] *= 2 # double the CO2 concentration
spinup.radiation.update_heatingrates(spinup.atmosphere)
instant_forcing = -(spinup.radiation["lw_flxu"][-1] - olr_ref)
```
Expand Down Expand Up @@ -94,7 +94,7 @@ The effective forcing includes the so called "stratospheric adjustment".
One can simulated by keeping the surface temperature fixed but allowing the atmopsheric temperature to adjust to the increased CO2 concentration.

```{code-cell} ipython3
perturbed = konrad.RCE(atmosphere.copy(), timestep='24h',max_duration='150d')
perturbed = konrad.RCE(spinup.atmosphere, timestep='24h',max_duration='150d')
perturbed.run()
effective_forcing = -(perturbed.radiation["lw_flxu"][-1] - olr_ref)
Expand Down
4 changes: 3 additions & 1 deletion howto/getting_started.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,9 @@ Finally, we can plot the RCE state and compare it to the inital (standard) atmop

```{code-cell} ipython3
fig, ax = plt.subplots()
plots.profile_p_log(atmosphere['plev'], atmosphere['T'][-1, :])
plots.profile_p_log(atmosphere['plev'], atmosphere['T'][-1, :], label="Init. state")
plots.profile_p_log(rce.atmosphere['plev'], rce.atmosphere['T'][-1, :], label="RCE")
ax.legend()
ax.set_xlabel(r"$T$ / K")
ax.set_ylabel("$p$ / hPa")
```
8 changes: 4 additions & 4 deletions howto/humidity.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,13 +58,13 @@ $Q_r$ is a decisive quantity in climate science as it destabilizies the atmosphe

```{code-cell} ipython3
fig, (ax0, ax1) = plt.subplots(ncols=2, sharey=True)
plots.profile_p_log(atmosphere['plev'], atmosphere['H2O'][-1, :], ax=ax0)
plots.profile_p_log(rce.atmosphere['plev'], rce.atmosphere['H2O'][-1, :], ax=ax0)
ax0.set_xlabel(r"$q$ / VMR")
ax0.set_xscale("log")
ax0.set_ylabel("$p$ / hPa")
ax1.axvline(0, color="k", linewidth=0.8)
plots.profile_p_log(atmosphere['plev'], rce.radiation["net_htngrt"][-1, :], ax=ax1)
plots.profile_p_log(rce.atmosphere['plev'], rce.radiation["net_htngrt"][-1, :], ax=ax1)
ax1.set_xlim(-2, 0.5)
ax1.set_xlabel(r"$Q_\mathrm{r}$ / (K/day)")
```
Expand All @@ -90,12 +90,12 @@ rce = konrad.RCE(
rce.run() # Start the simulation.
fig, (ax0, ax1) = plt.subplots(ncols=2, sharey=True)
plots.profile_p_log(atmosphere['plev'], atmosphere['H2O'][-1, :], ax=ax0)
plots.profile_p_log(rce.atmosphere['plev'], rce.atmosphere['H2O'][-1, :], ax=ax0)
ax0.set_xlabel(r"$q$ / VMR")
ax0.set_ylabel("$p$ / hPa")
ax1.axvline(0, color="k", linewidth=0.8)
plots.profile_p_log(atmosphere['plev'], rce.radiation["net_htngrt"][-1, :], ax=ax1)
plots.profile_p_log(rce.atmosphere['plev'], rce.radiation["net_htngrt"][-1, :], ax=ax1)
ax1.set_xlim(-2, 0.5)
ax1.set_xlabel(r"$Q_\mathrm{r}$ / (K/day)")
```
6 changes: 3 additions & 3 deletions howto/lapserate.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ for lapserate in [6.5, 8, 10]:
)
rce.run() # Start the simulation.
plots.profile_p_log(atmosphere['plev'], atmosphere['T'][-1, :])
plots.profile_p_log(rce.atmosphere['plev'], rce.atmosphere['T'][-1, :])
ax.set_xlabel(r"$T$ / K")
ax.set_ylabel("$p$ / hPa")
```
Expand All @@ -79,7 +79,7 @@ rce = konrad.RCE(
rce.run() # Start the simulation.
fig, ax = plt.subplots()
plots.profile_p_log(atmosphere['plev'], atmosphere['T'][-1, :])
plots.profile_p_log(rce.atmosphere['plev'], rce.atmosphere['T'][-1, :])
ax.set_xlabel(r"$T$ / K")
ax.set_ylabel("$p$ / hPa")
```
Expand All @@ -106,7 +106,7 @@ for Ts in [280, 290, 300]:
)
rce.run() # Start the simulation.
plots.profile_p_log(atmosphere['plev'], atmosphere['T'][-1, :])
plots.profile_p_log(rce.atmosphere['plev'], rce.atmosphere['T'][-1, :])
ax.set_xlabel(r"$T$ / K")
ax.set_ylabel("$p$ / hPa")
```
2 changes: 1 addition & 1 deletion howto/netcdf_output.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,5 +92,5 @@ rce = konrad.RCE(
rce.run()
# Plot adjusted state
plots.profile_p_log(atmosphere["plev"], atmosphere["T"][-1])
plots.profile_p_log(rce.atmosphere["plev"], rce.atmosphere["T"][-1])
```
14 changes: 7 additions & 7 deletions howto/ozone.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,15 +44,15 @@ for Ts in [285, 295, 305]:
)
rce.run()
l, = plots.profile_p_log(atmosphere["plev"], atmosphere["T"][-1], ax=ax0)
l, = plots.profile_p_log(rce.atmosphere["plev"], rce.atmosphere["T"][-1], ax=ax0)
ax0.set_xlabel(r"$T$ / K")
ax0.set_xlim(180, 306)
ax0.set_ylabel("$p$ / hPa")
ax0.set_ylim(bottom=atmosphere["plev"].max())
plots.profile_p_log(
atmosphere["plev"],
atmosphere["O3"][-1] * 1e6,
rce.atmosphere["plev"],
rce.atmosphere["O3"][-1] * 1e6,
label=f"{Ts} K",
color=l.get_color(),
ax=ax1,
Expand Down Expand Up @@ -81,15 +81,15 @@ for Ts in [285, 295, 305]:
)
rce.run()
l, = plots.profile_p_log(atmosphere["plev"], atmosphere["T"][-1], ax=ax0)
l, = plots.profile_p_log(rce.atmosphere["plev"], rce.atmosphere["T"][-1], ax=ax0)
ax0.set_xlabel(r"$T$ / K")
ax0.set_xlim(180, 306)
ax0.set_ylabel("$p$ / hPa")
ax0.set_ylim(bottom=atmosphere["plev"].max())
ax0.set_ylim(bottom=rce.atmosphere["plev"].max())
plots.profile_p_log(
atmosphere["plev"],
atmosphere["O3"][-1] * 1e6,
rce.atmosphere["plev"],
rce.atmosphere["O3"][-1] * 1e6,
label=f"{Ts} K",
color=l.get_color(),
ax=ax1,
Expand Down
18 changes: 0 additions & 18 deletions konrad/atmosphere.py
Original file line number Diff line number Diff line change
Expand Up @@ -284,24 +284,6 @@ def refine_plev(self, phlev, **kwargs):

return new_atmosphere

def copy(self):
"""Create a copy of the atmosphere.
Returns:
konrad.atmosphere: copy of the atmosphere
"""
datadict = dict()
datadict["phlev"] = copy(self["phlev"]) # Copy pressure grid.

# Create copies (and not references) of all atmospheric variables.
for variable in self.atmosphere_variables:
datadict[variable] = copy(self[variable]).ravel()

# Create a new atmosphere object from the filled data directory.
new_atmosphere = type(self).from_dict(datadict)

return new_atmosphere

def calculate_height(self):
"""Calculate the geopotential height."""
g = constants.earth_standard_gravity
Expand Down
5 changes: 5 additions & 0 deletions konrad/component.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import copy
import operator
from collections.abc import Hashable

Expand Down Expand Up @@ -224,3 +225,7 @@ def get(self, variable, default=None, keepdims=True):
raise KeyError(f"'{variable}' not found and no default given.")

return values if keepdims else values.ravel()

def copy(self):
"""Return a deepcopy of the component."""
return copy.deepcopy(self)
4 changes: 2 additions & 2 deletions konrad/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ def __init__(
# Sub-model initialisation

# Atmosphere
self.atmosphere = atmosphere
self.atmosphere = atmosphere.copy()

# Radiation
if radiation is None:
Expand All @@ -171,7 +171,7 @@ def __init__(
# Surface
self.surface = utils.return_if_type(
surface, "surface", Surface, FixedTemperature()
)
).copy()

# Cloud
self.cloud = utils.return_if_type(
Expand Down
11 changes: 11 additions & 0 deletions konrad/test/test_atmosphere.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,14 @@ def test_refine_plev(self, atmosphere_obj):
atmosphere_new = atmosphere_obj.refine_plev(phlev=phlev)

# TODO Add a proper test of values

def test_copy(self, atmosphere_obj):
"""Test deepcopy of atmosphere component."""
atmosphere_copy = atmosphere_obj.copy()

# Check if copied data is equal
assert np.array_equal(atmosphere_obj["T"], atmosphere_copy["T"])

# Check if copied data is independent
atmosphere_obj["T"][:] += 1.0
assert not np.array_equal(atmosphere_obj["T"], atmosphere_copy["T"])
12 changes: 12 additions & 0 deletions konrad/test/test_surface.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,15 @@ def test_init(self):
for t in init_args:
surf = surface.FixedTemperature(temperature=t)
assert np.array_equal(surf["temperature"], np.array([280.0], dtype=float))

def test_copy(self):
"""Test deepcopy of surface component."""
surf = surface.FixedTemperature(temperature=288.)
surf_copy = surf.copy()

# Check if copied data is equal
assert np.array_equal(surf["temperature"], surf_copy["temperature"])

# Check if copied data is independent
surf["temperature"][:] += 1.0
assert not np.array_equal(surf["temperature"], surf_copy["temperature"])

0 comments on commit bd11e2a

Please sign in to comment.