Skip to content

Commit

Permalink
refactor(netcdf): sync data, revise logger and exceptions
Browse files Browse the repository at this point in the history
  • Loading branch information
mwtoews committed Sep 8, 2021
1 parent 452d9ab commit ba69749
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 59 deletions.
6 changes: 4 additions & 2 deletions autotest/t027_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -380,8 +380,10 @@ def test_export():
if netCDF4 is not None:
fcw = m.wel.export(os.path.join(cpth, "MNW2-Fig28_well.nc"))
fcw.write()
fcm = m.mnw2.export(os.path.join(cpth, "MNW2-Fig28.nc"))
fcm.write()
fpth = os.path.join(cpth, "MNW2-Fig28.nc")
# test context statement
with m.mnw2.export(fpth):
pass
fpth = os.path.join(cpth, "MNW2-Fig28.nc")
nc = netCDF4.Dataset(fpth)
assert np.array_equal(
Expand Down
111 changes: 54 additions & 57 deletions flopy/export/netcdf.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ def __init__(self, filename, echo=False):
elif filename:
self.f = open(filename, "w", 0) # unbuffered
self.t = datetime.now()
self.log("opening " + str(filename) + " for logging")
self.log(f"opening {filename} for logging")
else:
self.filename = None

Expand All @@ -73,21 +73,18 @@ def log(self, phrase):
the thing that happened
"""
pass
t = datetime.now()
if phrase in self.items.keys():
s = f"{t} finished: {phrase}, took: {t - self.items[phrase]}\n"
t0 = self.items.pop(phrase)
s = f"{t} finished: {phrase}, took: {t - t0}\n"
if self.echo:
print(s)
print(s, end="")
if self.filename:
self.f.write(s)
self.items.pop(phrase)
else:
s = str(t) + " starting: " + str(phrase) + "\n"
s = f"{t} starting: {phrase}\n"
if self.echo:
print(
s,
)
print(s, end="")
if self.filename:
self.f.write(s)
self.items[phrase] = copy.deepcopy(t)
Expand All @@ -102,11 +99,9 @@ def warn(self, message):
the warning text
"""
s = str(datetime.now()) + " WARNING: " + message + "\n"
s = f"{datetime.now()} WARNING: {message}\n"
if self.echo:
print(
s,
)
print(s, end="")
if self.filename:
self.f.write(s)
return
Expand Down Expand Up @@ -195,23 +190,21 @@ def __init__(

try:
import dateutil.parser
except:
print(
except ImportError:
raise ImportError(
"python-dateutil is not installed\n"
"try pip install python-dateutil"
)
return

self.start_datetime = self._dt_str(
dateutil.parser.parse(self.model_time.start_datetime)
)
self.logger.warn(f"start datetime:{self.start_datetime!s}")
dt = dateutil.parser.parse(self.model_time.start_datetime)
self.start_datetime = dt.strftime("%Y-%m-%dT%H:%M:%SZ")
self.logger.log(f"start datetime:{self.start_datetime}")

proj4_str = self.model_grid.proj4
if proj4_str is None:
proj4_str = "epsg:4326"
self.log(
"Warning: model has no coordinate reference system specified. "
self.logger.warn(
"model has no coordinate reference system specified. "
f"Using default proj4 string: {proj4_str}"
)
self.proj4_str = proj4_str
Expand All @@ -237,6 +230,14 @@ def __init__(
self.initialize_file(time_values=self.time_values_arg)
self.log("initializing file")

def __enter__(self):
"""Enter context with statement, returning with an open dataset."""
return self

def __exit__(self, *exc):
"""Exit context with statement, write and close dataset."""
self.write()

def __add__(self, other):
new_net = NetCdf.zeros_like(self)
if np.isscalar(other) or isinstance(other, np.ndarray):
Expand All @@ -253,6 +254,7 @@ def __add__(self, other):
raise Exception(
f"NetCdf.__add__(): unrecognized other:{type(other)}"
)
new_net.sync()
return new_net

def __sub__(self, other):
Expand All @@ -271,6 +273,7 @@ def __sub__(self, other):
raise Exception(
f"NetCdf.__sub__(): unrecognized other:{type(other)}"
)
new_net.sync()
return new_net

def __mul__(self, other):
Expand All @@ -289,6 +292,7 @@ def __mul__(self, other):
raise Exception(
f"NetCdf.__mul__(): unrecognized other:{type(other)}"
)
new_net.sync()
return new_net

def __div__(self, other):
Expand All @@ -312,7 +316,8 @@ def __truediv__(self, other):
raise Exception(
f"NetCdf.__sub__(): unrecognized other:{type(other)}"
)
return new_net
new_net.sync()
return new_net

def append(self, other, suffix="_1"):
assert isinstance(other, NetCdf) or isinstance(other, dict)
Expand Down Expand Up @@ -367,13 +372,14 @@ def append(self, other, suffix="_1"):
new_var[:] = array
except:
new_var[:, 0] = array

self.nc.sync()
return

def copy(self, output_filename):
new_net = NetCdf.zeros_like(self, output_filename=output_filename)
for vname in self.var_attr_dict.keys():
new_net.nc.variables[vname][:] = self.nc.variables[vname][:]
new_net.sync()
return new_net

@classmethod
Expand Down Expand Up @@ -416,6 +422,7 @@ def zeros_like(
if attr not in new_net.nc.ncattrs():
global_attrs[attr] = other.nc[attr]
new_net.add_global_attributes(global_attrs)
new_net.sync()
return new_net

@classmethod
Expand Down Expand Up @@ -477,16 +484,11 @@ def difference(
other are carried through to the new instance
"""
import netCDF4

assert (
self.nc is not None
), "can't call difference() if nc hasn't been populated"
try:
import netCDF4
except Exception as e:
mess = f"error import netCDF4: {e!s}"
self.logger.warn(mess)
raise Exception(mess)

if isinstance(other, str):
assert os.path.exists(other), f"filename 'other' not found:{other}"
Expand Down Expand Up @@ -600,14 +602,7 @@ def difference(

var[:] = d_data
self.log(f"processing variable {vname}")

def _dt_str(self, dt):
"""for datetime to string for year < 1900"""
dt_str = (
f"{dt.year:04d}-{dt.month:02d}-{dt.day:02d}T"
f"{dt.hour:02d}:{dt.minute:02d}:{dt.second:02}Z"
)
return dt_str
new_net.sync()

def write(self):
"""write the nc object to disk"""
Expand All @@ -622,8 +617,8 @@ def write(self):
try:
if self.nc.attributes.get(k) is not None:
self.nc.setncattr(k, v)
except Exception:
self.logger.warn(f"error setting global attribute {k}")
except Exception as e:
self.logger.warn(f"error setting global attribute {k}: {e!s}")

self.nc.sync()
self.nc.close()
Expand Down Expand Up @@ -687,9 +682,7 @@ def initialize_geometry(self):
try:
import pyproj
except ImportError as e:
raise ImportError(
"NetCdf error importing pyproj module:\n" + str(e)
)
raise ImportError("NetCdf error importing pyproj module") from e
from distutils.version import LooseVersion

# Check if using newer pyproj version conventions
Expand Down Expand Up @@ -775,17 +768,15 @@ def initialize_file(self, time_values=None):
self.log("initializing geometry")
try:
import netCDF4
except Exception as e:
except ImportError as e:
self.logger.warn("error importing netCDF module")
msg = "NetCdf error importing netCDF4 module:\n" + str(e)
raise Exception(msg)
raise ImportError("NetCdf error importing netCDF4 module") from e

# open the file for writing
try:
self.nc = netCDF4.Dataset(self.output_filename, "w")
except Exception as e:
msg = f"error creating netcdf dataset:\n{e!s}"
raise Exception(msg)
raise Exception("error creating netcdf dataset") from e

# write some attributes
self.log("setting standard attributes")
Expand All @@ -795,7 +786,7 @@ def initialize_file(self, time_values=None):
f"CF-1.6, ACDD-1.3, flopy {flopy.__version__}",
)
self.nc.setncattr(
"date_created", datetime.utcnow().strftime("%Y-%m-%dT%H:%M:00Z")
"date_created", datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%SZ")
)
self.nc.setncattr("geospatial_vertical_positive", str(self.z_positive))
min_vertical = np.min(self.zs)
Expand All @@ -807,8 +798,8 @@ def initialize_file(self, time_values=None):
for k, v in self.global_attributes.items():
try:
self.nc.setncattr(k, v)
except:
self.logger.warn(f"error setting global attribute {k}")
except Exception as e:
self.logger.warn(f"error setting global attribute {k}: {e!s}")
self.global_attributes = {}
self.log("setting standard attributes")

Expand Down Expand Up @@ -1002,6 +993,7 @@ def initialize_file(self, time_values=None):
exp.existingDataField = "elevation"
exp._CoordinateTransformType = "vertical"
exp._CoordinateAxes = "layer"
self.nc.sync()
return

def initialize_group(
Expand Down Expand Up @@ -1129,6 +1121,7 @@ def initialize_group(
dimensions=dim_names,
)
var[:] = np.asarray(dimension_data[dim])
self.nc.sync()

@staticmethod
def normalize_name(name):
Expand Down Expand Up @@ -1212,11 +1205,13 @@ def create_group_variable(
for k, v in attributes.items():
try:
var.setncattr(k, v)
except:
except Exception as e:
self.logger.warn(
f"error setting attribute{k} for group {group} variable {name}"
"error setting attribute "
f"{k} for group {group} variable {name}: {e!s}"
)
self.log(f"creating group {group} variable: {name}")
self.nc.sync()

return var

Expand Down Expand Up @@ -1275,7 +1270,7 @@ def create_variable(
if name in self.nc.variables.keys():
raise Exception(f"duplicate variable name: {name}")

self.log("creating variable: " + str(name))
self.log(f"creating variable: {name}")
assert (
precision_str in PRECISION_STRS
), "netcdf.create_variable() error: precision string {0} not in {1}".format(
Expand Down Expand Up @@ -1310,11 +1305,12 @@ def create_variable(
for k, v in attributes.items():
try:
var.setncattr(k, v)
except:
except Exception as e:
self.logger.warn(
f"error setting attribute{k} for variable {name}"
f"error setting attribute{k} for variable {name}: {e!s}"
)
self.log("creating variable: " + str(name))
self.log(f"creating variable: {name}")
self.nc.sync()
return var

def add_global_attributes(self, attr_dict):
Expand Down Expand Up @@ -1346,6 +1342,7 @@ def add_global_attributes(self, attr_dict):
self.log("setting global attributes")
self.nc.setncatts(attr_dict)
self.log("setting global attributes")
self.nc.sync()

def add_sciencebase_metadata(self, id, check=True):
"""Add metadata from ScienceBase using the
Expand Down

0 comments on commit ba69749

Please sign in to comment.