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

Add deepcopy #225

Merged
merged 5 commits into from
Jul 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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"])
Loading