Newer
Older
"""Point-wise Ocean Heat Content in a specified ocean thickness (J/m-2)"""
Javier Vegas-Regidor
committed
import numpy as np
from earthdiagnostics.box import Box
from earthdiagnostics.diagnostic import (
Diagnostic,
DiagnosticIntOption,
DiagnosticBasinListOption,
)
from earthdiagnostics.modelingrealm import ModelingRealms
Javier Vegas-Regidor
committed
from diagonals import ohc
from diagonals.mesh_helpers.nemo import Nemo
import netCDF4
Javier Vegas-Regidor
committed
Javier Vegas-Regidor
committed
class HeatContentLayer(Diagnostic):
"""
Point-wise Ocean Heat Content in a specified ocean thickness (J/m-2)
:original author: Isabel Andreu Burillo
:contributor: Virginie Guemas <virginie.guemas@bsc.es>
:contributor: Eleftheria Exarchou <eleftheria.exarchou@bsc.es>
Javier Vegas-Regidor
committed
:contributor: Javier Vegas-Regidor<javier.vegas@bsc.es>
:created: June 2012
:last modified: June 2016
:param data_manager: data management object
:type data_manager: DataManager
:param startdate: startdate
:type startdate: str
:param member: member number
:type member: int
:param chunk: chunk's number
:type chunk: int
:param box: box to use for the calculations
:type box: Box
Javier Vegas-Regidor
committed
"""
"Diagnostic alias for the configuration file"
def __init__(
self,
data_manager,
startdate,
member,
chunk,
box,
areas,
weight,
layers,
basins,
data_convention,
min_level,
max_level,
):
Javier Vegas-Regidor
committed
Diagnostic.__init__(self, data_manager)
self.startdate = startdate
self.member = member
self.chunk = chunk
Javier Vegas-Regidor
committed
self.box = box
self.layers = layers
self.basins = basins
self.min_level = min_level
self.max_level = max_level
Javier Vegas-Regidor
committed
def __str__(self):
return (
f"Heat content layer Startdate: {self.startdate} "
f"Member: {self.member} Chunk: {self.chunk} "
f"Box: {self.box}"
)
Javier Vegas-Regidor
committed
@classmethod
def generate_jobs(cls, diags, options):
"""
Create a job for each chunk to compute the diagnostic
Javier Vegas-Regidor
committed
:param diags: Diagnostics manager class
:type diags: Diags
:param options: minimum depth, maximum depth, basin=Global
Javier Vegas-Regidor
committed
:type options: list[str]
"""
DiagnosticIntOption("min_depth"),
DiagnosticIntOption("max_depth"),
DiagnosticBasinListOption("basins", "global"),
Javier Vegas-Regidor
committed
options = cls.process_options(options, options_available)
Javier Vegas-Regidor
committed
box = Box(True)
box.min_depth = options["min_depth"]
box.max_depth = options["max_depth"]
basins = options["basins"]
layers = ((box.min_depth, box.max_depth),)
masks = {}
basins.sort()
for basin in basins:
masks[basin] = Utils.get_mask(basin)
areacello = mesh.get_areacello()
areas = ohc.get_basin_area(areacello, masks)
Javier Vegas-Regidor
committed
job_list = list()
e3t = mesh.get_k_length()
mask = mesh.get_landsea_mask()
weight = ohc.get_weights(layers, mask, e3t, depth)
max_level, min_level = cls._get_used_levels(weight)
weight[0] = weight[0][:, min_level:max_level, :, :]
for (
startdate,
member,
chunk,
) in diags.config.experiment.get_chunk_list():
job_list.append(
HeatContentLayer(
diags.data_manager,
startdate,
member,
chunk,
box,
areas,
weight,
layers,
basins,
diags.config.data_convention,
min_level,
max_level,
)
)
@classmethod
def _get_mesh_info(cls):
# mask = Utils.get_mask(options['basin'])
mask = handler.variables["tmask"][:]
if "e3t" in handler.variables:
e3t = handler.variables["e3t"][:]
elif "e3t_0" in handler.variables:
e3t = handler.variables["e3t_0"][:]
raise Exception("e3t variable can not be found")
if "gdepw" in handler.variables:
depth = handler.variables["gdepw"][:]
elif "gdepw_0" in handler.variables:
depth = handler.variables["gdepw_0"][:]
raise Exception("gdepw variable can not be found")
e3t_3d = e3t.shape != depth.shape
if e3t_3d:
mask = e3t_3d * mask
else:
e3t = e3t[0, :]
while len(depth.shape) < 4:
depth = np.expand_dims(depth, -1)
handler.close()
return depth, e3t, mask
self.thetao = self.request_chunk(
ModelingRealms.ocean,
"thetao",
self.startdate,
self.member,
self.chunk,
)
self.heatc = self.declare_chunk(
ModelingRealms.ocean,
"heatc",
self.startdate,
self.member,
self.chunk,
box=self.box,
)
self.heatcsum = self.declare_chunk(
ModelingRealms.ocean,
"heatcsum",
self.startdate,
self.member,
self.chunk,
box=self.box,
)
@classmethod
def _get_used_levels(cls, weight):
# Now we will reduce to the levels with any weight != 0 to avoid
# loading too much data on memory
levels = weight[0].shape[1]
min_level = 0
while min_level < levels and not weight[0][:, min_level, :].any():
min_level += 1
max_level = min_level
while (
max_level < (levels - 1) and weight[0][:, max_level + 1, :].any()
):
max_level += 1
return max_level, min_level
Utils.copy_file(self.thetao.local_file, thetao_file)
Javier Vegas-Regidor
committed
Utils.convert_units(handler.variables["thetao"], "K")
heatc_sl, heatc_sl_1d = ohc.compute(
self.layers,
self.weight,
handler.variables["thetao"][
:, self.min_level:self.max_level, :, :
],
self.areas,
)
Javier Vegas-Regidor
committed
handler_results = Utils.open_cdf(results, "w")
lat_name = next(
alias
for alias in ("lat", "latitude")
if alias in handler.variables.keys()
)
lon_name = next(
alias
for alias in ("lon", "longitude")
if alias in handler.variables.keys()
)
Utils.copy_variable(handler, handler_results, "time", True, True)
Utils.copy_variable(handler, handler_results, "i", False, True)
Utils.copy_variable(handler, handler_results, "j", False, True)
Utils.copy_variable(handler, handler_results, lat_name, True, True)
Utils.copy_variable(handler, handler_results, lon_name, True, True)
var = handler_results.createVariable(
"heatc", float, ("time", "j", "i"), fill_value=1.0e20
)
var.units = "J m-2" ""
var.coordinates = " ".join((lat_name, lon_name))
# temporary fix, needs to loop over layers
handler_results.variables["heatc"][:] = heatc_sl[0]
Javier Vegas-Regidor
committed
handler_results.close()
results_1d = TempFile.get()
handler_results_1d = Utils.open_cdf(results_1d, "w")
Utils.copy_variable(handler, handler_results_1d, "time", True, True)
handler_results_1d.createDimension("region", len(self.basins))
handler_results_1d.createDimension("region_length", 50)
var_region = handler_results_1d.createVariable(
"region", "S1", ("region", "region_length")
)
var_ohc_1d = handler_results_1d.createVariable(
"heatcsum", float, ("time", "region",),
)
handler_results_1d.sync()
for i, basin in enumerate(self.basins):
var_region[i, ...] = netCDF4.stringtoarr(basin.name, 50)
var_ohc_1d[..., i] = heatc_sl_1d[i]
handler_results_1d.close()