Commit c6897a12 authored by Le Roux Erwan's avatar Le Roux Erwan
Browse files

[SCM MODELS DATA] refactor abstract study file

parent 2872efd9
No related merge requests found
Showing with 205 additions and 195 deletions
+205 -195
...@@ -16,7 +16,8 @@ from matplotlib.colors import Normalize ...@@ -16,7 +16,8 @@ from matplotlib.colors import Normalize
from netCDF4 import Dataset from netCDF4 import Dataset
from experiment.meteo_france_data.scm_models_data.abstract_variable import AbstractVariable from experiment.meteo_france_data.scm_models_data.abstract_variable import AbstractVariable
from experiment.meteo_france_data.scm_models_data.scm_constants import ALTITUDES, ZS_INT_23, ZS_INT_MASK, LONGITUDES, LATITUDES from experiment.meteo_france_data.scm_models_data.scm_constants import ALTITUDES, ZS_INT_23, ZS_INT_MASK, LONGITUDES, \
LATITUDES
from experiment.meteo_france_data.visualization.utils import get_km_formatter from experiment.meteo_france_data.visualization.utils import get_km_formatter
from extreme_estimator.extreme_models.margin_model.margin_function.abstract_margin_function import \ from extreme_estimator.extreme_models.margin_model.margin_function.abstract_margin_function import \
AbstractMarginFunction AbstractMarginFunction
...@@ -48,84 +49,12 @@ class AbstractStudy(object): ...@@ -48,84 +49,12 @@ class AbstractStudy(object):
self.year_max = year_max self.year_max = year_max
self.multiprocessing = multiprocessing self.multiprocessing = multiprocessing
def write_to_file(self, df: pd.DataFrame): """ Annual maxima """
if not op.exists(self.result_full_path):
os.makedirs(self.result_full_path, exist_ok=True)
df.to_csv(op.join(self.result_full_path, 'merged_array_{}_altitude.csv'.format(self.altitude)))
""" Data """
@property
def df_all_daily_time_series_concatenated(self) -> pd.DataFrame:
df_list = [pd.DataFrame(time_serie, columns=self.study_massif_names) for time_serie in
self.year_to_daily_time_serie_array.values()]
df_concatenated = pd.concat(df_list)
return df_concatenated
@property @property
def observations_annual_maxima(self) -> AnnualMaxima: def observations_annual_maxima(self) -> AnnualMaxima:
return AnnualMaxima(df_maxima_gev=pd.DataFrame(self.year_to_annual_maxima, index=self.study_massif_names)) return AnnualMaxima(df_maxima_gev=pd.DataFrame(self.year_to_annual_maxima, index=self.study_massif_names))
@property
def df_annual_total(self) -> pd.DataFrame:
return pd.DataFrame(self.year_to_annual_total, index=self.study_massif_names).transpose()
def annual_aggregation_function(self, *args, **kwargs):
raise NotImplementedError()
""" Load some attributes only once """
@property
def year_to_dataset_ordered_dict(self) -> OrderedDict:
print('This code is quite long... '
'You should consider year_to_variable which is way faster when multiprocessing=True')
# Map each year to the correspond netCDF4 Dataset
path_files, ordered_years = self.ordered_years_and_path_files()
datasets = [Dataset(path_file) for path_file in path_files]
return OrderedDict(zip(ordered_years, datasets))
def ordered_years_and_path_files(self):
nc_files = [(int(f.split('_')[-2][:4]), f) for f in os.listdir(self.study_full_path) if f.endswith('.nc')]
ordered_years, path_files = zip(*[(year, op.join(self.study_full_path, nc_file))
for year, nc_file in sorted(nc_files, key=lambda t: t[0])
if self.year_min <= year < self.year_max])
return path_files, ordered_years
@property
def ordered_years(self):
return self.ordered_years_and_path_files()[1]
@cached_property
def year_to_variable_array(self) -> OrderedDict:
# Map each year to the variable array
path_files, ordered_years = self.ordered_years_and_path_files()
if self.multiprocessing:
with Pool(NB_CORES) as p:
variables = p.map(self.load_variables, path_files)
else:
variables = [self.load_variables(path_file) for path_file in path_files]
return OrderedDict(zip(ordered_years, variables))
def load_variables(self, path_file):
dataset = Dataset(path_file)
keyword = self.load_keyword()
if isinstance(keyword, str):
return np.array(dataset.variables[keyword])
else:
return [np.array(dataset.variables[k]) for k in keyword]
def load_keyword(self):
return self.variable_class.keyword()
@property
def start_year_and_stop_year(self) -> Tuple[int, int]:
ordered_years = self.ordered_years
return ordered_years[0], ordered_years[-1]
@cached_property
def year_to_daily_time_serie_array(self) -> OrderedDict:
return self._year_to_daily_time_serie_array
@cached_property @cached_property
def year_to_annual_maxima(self) -> OrderedDict: def year_to_annual_maxima(self) -> OrderedDict:
# Map each year to an array of size nb_massif # Map each year to an array of size nb_massif
...@@ -134,6 +63,15 @@ class AbstractStudy(object): ...@@ -134,6 +63,15 @@ class AbstractStudy(object):
year_to_annual_maxima[year] = time_serie.max(axis=0) year_to_annual_maxima[year] = time_serie.max(axis=0)
return year_to_annual_maxima return year_to_annual_maxima
""" Annual total """
@property
def df_annual_total(self) -> pd.DataFrame:
return pd.DataFrame(self.year_to_annual_total, index=self.study_massif_names).transpose()
def annual_aggregation_function(self, *args, **kwargs):
raise NotImplementedError()
@cached_property @cached_property
def year_to_annual_total(self) -> OrderedDict: def year_to_annual_total(self) -> OrderedDict:
# Map each year to an array of size nb_massif # Map each year to an array of size nb_massif
...@@ -145,10 +83,15 @@ class AbstractStudy(object): ...@@ -145,10 +83,15 @@ class AbstractStudy(object):
def apply_annual_aggregation(self, time_serie): def apply_annual_aggregation(self, time_serie):
return self.annual_aggregation_function(time_serie, axis=0) return self.annual_aggregation_function(time_serie, axis=0)
def instantiate_variable_object(self, variable_array) -> AbstractVariable: """ Load daily observations """
return self.variable_class(variable_array)
""" Private methods to be overwritten """ @cached_property
def year_to_daily_time_serie_array(self) -> OrderedDict:
return self._year_to_daily_time_serie_array
@property
def _year_to_max_daily_time_serie(self) -> OrderedDict:
return self._year_to_daily_time_serie_array
@property @property
def _year_to_daily_time_serie_array(self) -> OrderedDict: def _year_to_daily_time_serie_array(self) -> OrderedDict:
...@@ -167,78 +110,117 @@ class AbstractStudy(object): ...@@ -167,78 +110,117 @@ class AbstractStudy(object):
year_to_daily_time_serie_array[year] = daily_time_serie year_to_daily_time_serie_array[year] = daily_time_serie
return year_to_daily_time_serie_array return year_to_daily_time_serie_array
@property def instantiate_variable_object(self, variable_array) -> AbstractVariable:
def _year_to_max_daily_time_serie(self) -> OrderedDict: return self.variable_class(variable_array)
return self._year_to_daily_time_serie_array
""" Load Variables and Datasets """
@cached_property
def year_to_variable_array(self) -> OrderedDict:
# Map each year to the variable array
path_files, ordered_years = self.ordered_years_and_path_files
if self.multiprocessing:
with Pool(NB_CORES) as p:
variables = p.map(self.load_variables, path_files)
else:
variables = [self.load_variables(path_file) for path_file in path_files]
return OrderedDict(zip(ordered_years, variables))
def load_variables(self, path_file):
dataset = Dataset(path_file)
keyword = self.load_keyword()
if isinstance(keyword, str):
return np.array(dataset.variables[keyword])
else:
return [np.array(dataset.variables[k]) for k in keyword]
########## def load_keyword(self):
return self.variable_class.keyword()
@property @property
def study_massif_names(self) -> List[str]: def year_to_dataset_ordered_dict(self) -> OrderedDict:
return self.altitude_to_massif_names[self.altitude] print('This code is quite long... '
'You should consider year_to_variable which is way faster when multiprocessing=True')
# Map each year to the correspond netCDF4 Dataset
path_files, ordered_years = self.ordered_years_and_path_files
datasets = [Dataset(path_file) for path_file in path_files]
return OrderedDict(zip(ordered_years, datasets))
@cached_property @cached_property
def all_massif_names(self) -> List[str]: def ordered_years_and_path_files(self):
""" nc_files = [(int(f.split('_')[-2][:4]), f) for f in os.listdir(self.study_full_path) if f.endswith('.nc')]
Pour l'identification des massifs, le numéro de la variable massif_num correspond à celui de l'attribut num_opp ordered_years, path_files = zip(*[(year, op.join(self.study_full_path, nc_file))
""" for year, nc_file in sorted(nc_files, key=lambda t: t[0])
metadata_path = op.join(self.full_path, self.REANALYSIS_FOLDER, 'metadata') if self.year_min <= year < self.year_max])
dbf = Dbf5(op.join(metadata_path, 'massifs_alpes.dbf')) return path_files, ordered_years
df = dbf.to_dataframe().copy() # type: pd.DataFrame
dbf.f.close() """ Temporal properties """
df.sort_values(by='num_opp', inplace=True)
all_massif_names = list(df['nom'])
# Correct a massif name
all_massif_names[all_massif_names.index('Beaufortin')] = 'Beaufortain'
return all_massif_names
@property @property
def original_safran_massif_id_to_massif_name(self) -> Dict[int, str]: def ordered_years(self):
return {massif_id: massif_name for massif_id, massif_name in enumerate(self.all_massif_names)} return self.ordered_years_and_path_files[1]
@cached_property @property
def massifs_coordinates_for_display(self) -> AbstractSpatialCoordinates: def start_year_and_stop_year(self) -> Tuple[int, int]:
# Coordinate object that represents the massif coordinates in Lambert extended ordered_years = self.ordered_years
# extracted for a csv file, and used only for display purposes return ordered_years[0], ordered_years[-1]
df = self.load_df_centroid()
# Filter, keep massifs present at the altitude of interest """ Spatial properties """
df = df.loc[self.study_massif_names]
# Build coordinate object from df_centroid @property
return AbstractSpatialCoordinates.from_df(df) def study_massif_names(self) -> List[str]:
return self.altitude_to_massif_names[self.altitude]
@property @property
def df_massifs_longitude_and_latitude(self) -> pd.DataFrame: def df_massifs_longitude_and_latitude(self) -> pd.DataFrame:
# DataFrame object that represents the massif coordinates in degrees extracted from the SCM data # DataFrame object that represents the massif coordinates in degrees extracted from the SCM data
# Another way of getting the latitudes and longitudes could have been the following:
# any_ordered_dict = list(self.year_to_dataset_ordered_dict.values())[0] # any_ordered_dict = list(self.year_to_dataset_ordered_dict.values())[0]
# longitude = np.array(any_ordered_dict.variables['longitude']) # longitude = np.array(any_ordered_dict.variables['longitude'])
# latitude = np.array(any_ordered_dict.variables['latitude']) # latitude = np.array(any_ordered_dict.variables['latitude'])
longitude = np.array(LONGITUDES) longitude = np.array(LONGITUDES)
latitude = np.array(LATITUDES) latitude = np.array(LATITUDES)
index = self.altitude_to_massif_names[self.altitude]
columns = [AbstractSpatialCoordinates.COORDINATE_X, AbstractSpatialCoordinates.COORDINATE_Y] columns = [AbstractSpatialCoordinates.COORDINATE_X, AbstractSpatialCoordinates.COORDINATE_Y]
data = dict(zip(columns, [longitude[self.altitude_mask], latitude[self.altitude_mask]])) data = dict(zip(columns, [longitude[self.altitude_mask], latitude[self.altitude_mask]]))
return pd.DataFrame(data=data, index=index, columns=columns) return pd.DataFrame(data=data, index=self.study_massif_names, columns=columns)
def load_df_centroid(self) -> pd.DataFrame: @property
# Load df_centroid containing all the massif names def missing_massif_name(self):
df_centroid = pd.read_csv(op.join(self.map_full_path, 'coordonnees_massifs_alpes.csv')) return set(self.all_massif_names) - set(self.altitude_to_massif_names[self.altitude])
df_centroid.set_index('NOM', inplace=True)
# Check that the names of massifs are the same @cached_property
symmetric_difference = set(df_centroid.index).symmetric_difference(self.all_massif_names) def altitude_mask(self):
assert len(symmetric_difference) == 0, symmetric_difference altitude_mask = ZS_INT_MASK == self.altitude
# Sort the column in the order of the SAFRAN dataset assert np.sum(altitude_mask) == len(self.altitude_to_massif_names[self.altitude])
df_centroid = df_centroid.reindex(self.all_massif_names, axis=0) return altitude_mask
for coord_column in [AbstractCoordinates.COORDINATE_X, AbstractCoordinates.COORDINATE_Y]:
df_centroid.loc[:, coord_column] = df_centroid[coord_column].str.replace(',', '.').astype(float) """ Path properties """
return df_centroid
@property @property
def coordinate_id_to_massif_name(self) -> Dict[int, str]: def title(self):
df_centroid = self.load_df_centroid() return "{}/at altitude {}m ({} mountain chains)".format(self.variable_name, self.altitude,
return dict(zip(df_centroid['id'], df_centroid.index)) len(self.study_massif_names))
@property
def variable_name(self):
return self.variable_class.NAME + ' (in {})'.format(self.variable_unit)
@property
def variable_unit(self):
return self.variable_class.UNIT
""" Visualization methods """ """ Visualization methods """
@cached_property
def massifs_coordinates_for_display(self) -> AbstractSpatialCoordinates:
# Coordinate object that represents the massif coordinates in Lambert extended
# extracted for a csv file, and used only for display purposes
df = self.load_df_centroid()
# Filter, keep massifs present at the altitude of interest
df = df.loc[self.study_massif_names]
# Build coordinate object from df_centroid
return AbstractSpatialCoordinates.from_df(df)
def visualize_study(self, ax=None, massif_name_to_value=None, show=True, fill=True, replace_blue_by_white=True, def visualize_study(self, ax=None, massif_name_to_value=None, show=True, fill=True, replace_blue_by_white=True,
label=None, add_text=False, cmap=None, vmax=100, vmin=0): label=None, add_text=False, cmap=None, vmax=100, vmin=0):
if massif_name_to_value is None: if massif_name_to_value is None:
...@@ -300,49 +282,68 @@ class AbstractStudy(object): ...@@ -300,49 +282,68 @@ class AbstractStudy(object):
if show: if show:
plt.show() plt.show()
"""
CLASS ATTRIBUTES COMMON TO ALL OBJECTS
(written as object attributes/methods for simplicity)
"""
""" Path properties """
@property @property
def idx_to_coords_list(self): def relative_path(self) -> str:
df_massif = pd.read_csv(op.join(self.map_full_path, 'massifsalpes.csv')) return r'local/spatio_temporal_datasets'
coord_tuples = [(row_massif['idx'], row_massif[AbstractCoordinates.COORDINATE_X],
row_massif[AbstractCoordinates.COORDINATE_Y])
for _, row_massif in df_massif.iterrows()]
all_idxs = set([t[0] for t in coord_tuples])
return {idx: [coords for idx_loop, *coords in coord_tuples if idx == idx_loop] for idx in all_idxs}
@property @property
def all_coords_list(self): def full_path(self) -> str:
all_values = [] return get_full_path(relative_path=self.relative_path)
for e in self.idx_to_coords_list.values():
all_values.extend(e)
return list(zip(*all_values))
@property @property
def visualization_x_limits(self): def map_full_path(self) -> str:
return min(self.all_coords_list[0]), max(self.all_coords_list[0]) return op.join(self.full_path, 'map')
@property @property
def visualization_y_limits(self): def result_full_path(self) -> str:
return min(self.all_coords_list[1]), max(self.all_coords_list[1]) return op.join(self.full_path, 'results')
@property
def study_full_path(self) -> str:
assert self.model_name in ['Safran', 'Crocus']
study_folder = 'meteo' if self.model_name is 'Safran' else 'pro'
return op.join(self.full_path, self.REANALYSIS_FOLDER, study_folder)
""" Spatial properties """
@property
def original_safran_massif_id_to_massif_name(self) -> Dict[int, str]:
return {massif_id: massif_name for massif_id, massif_name in enumerate(self.all_massif_names)}
@cached_property @cached_property
def mask_french_alps(self): def all_massif_names(self) -> List[str]:
resolution = AbstractMarginFunction.VISUALIZATION_RESOLUTION """
mask_french_alps = np.zeros([resolution, resolution]) Pour l'identification des massifs, le numéro de la variable massif_num correspond à celui de l'attribut num_opp
for polygon in self.idx_to_coords_list.values(): """
xy_values = list(zip(*polygon)) metadata_path = op.join(self.full_path, self.REANALYSIS_FOLDER, 'metadata')
normalized_polygon = [] dbf = Dbf5(op.join(metadata_path, 'massifs_alpes.dbf'))
for values, (minlim, max_lim) in zip(xy_values, [self.visualization_x_limits, self.visualization_y_limits]): df = dbf.to_dataframe().copy() # type: pd.DataFrame
values -= minlim dbf.f.close()
values *= resolution / (max_lim - minlim) df.sort_values(by='num_opp', inplace=True)
normalized_polygon.append(values) all_massif_names = list(df['nom'])
normalized_polygon = list(zip(*normalized_polygon)) # Correct a massif name
img = Image.new('L', (resolution, resolution), 0) all_massif_names[all_massif_names.index('Beaufortin')] = 'Beaufortain'
ImageDraw.Draw(img).polygon(normalized_polygon, outline=1, fill=1) return all_massif_names
mask_massif = np.array(img)
mask_french_alps += mask_massif
return ~np.array(mask_french_alps, dtype=bool)
""" Some properties """ def load_df_centroid(self) -> pd.DataFrame:
# Load df_centroid containing all the massif names
df_centroid = pd.read_csv(op.join(self.map_full_path, 'coordonnees_massifs_alpes.csv'))
df_centroid.set_index('NOM', inplace=True)
# Check that the names of massifs are the same
symmetric_difference = set(df_centroid.index).symmetric_difference(self.all_massif_names)
assert len(symmetric_difference) == 0, symmetric_difference
# Sort the column in the order of the SAFRAN dataset
df_centroid = df_centroid.reindex(self.all_massif_names, axis=0)
for coord_column in [AbstractCoordinates.COORDINATE_X, AbstractCoordinates.COORDINATE_Y]:
df_centroid.loc[:, coord_column] = df_centroid[coord_column].str.replace(',', '.').astype(float)
return df_centroid
@cached_property @cached_property
def massif_name_to_altitudes(self) -> Dict[str, List[int]]: def massif_name_to_altitudes(self) -> Dict[str, List[int]]:
...@@ -364,49 +365,51 @@ class AbstractStudy(object): ...@@ -364,49 +365,51 @@ class AbstractStudy(object):
altitude_to_massif_names[altitude].append(massif_name) altitude_to_massif_names[altitude].append(massif_name)
return altitude_to_massif_names return altitude_to_massif_names
@property """ Visualization methods """
def missing_massif_name(self):
return set(self.all_massif_names) - set(self.altitude_to_massif_names[self.altitude])
@cached_property
def altitude_mask(self):
altitude_mask = ZS_INT_MASK == self.altitude
assert np.sum(altitude_mask) == len(self.altitude_to_massif_names[self.altitude])
return altitude_mask
@property
def title(self):
return "{}/at altitude {}m ({} mountain chains)".format(self.variable_name, self.altitude,
len(self.study_massif_names))
@property
def variable_name(self):
return self.variable_class.NAME + ' (in {})'.format(self.variable_unit)
@property @property
def variable_unit(self): def coordinate_id_to_massif_name(self) -> Dict[int, str]:
return self.variable_class.UNIT df_centroid = self.load_df_centroid()
return dict(zip(df_centroid['id'], df_centroid.index))
""" Some path properties """
@property @property
def relative_path(self) -> str: def idx_to_coords_list(self):
return r'local/spatio_temporal_datasets' df_massif = pd.read_csv(op.join(self.map_full_path, 'massifsalpes.csv'))
coord_tuples = [(row_massif['idx'], row_massif[AbstractCoordinates.COORDINATE_X],
row_massif[AbstractCoordinates.COORDINATE_Y])
for _, row_massif in df_massif.iterrows()]
all_idxs = set([t[0] for t in coord_tuples])
return {idx: [coords for idx_loop, *coords in coord_tuples if idx == idx_loop] for idx in all_idxs}
@property @property
def full_path(self) -> str: def all_coords_list(self):
return get_full_path(relative_path=self.relative_path) all_values = []
for e in self.idx_to_coords_list.values():
all_values.extend(e)
return list(zip(*all_values))
@property @property
def map_full_path(self) -> str: def visualization_x_limits(self):
return op.join(self.full_path, 'map') return min(self.all_coords_list[0]), max(self.all_coords_list[0])
@property @property
def result_full_path(self) -> str: def visualization_y_limits(self):
return op.join(self.full_path, 'results') return min(self.all_coords_list[1]), max(self.all_coords_list[1])
@property @cached_property
def study_full_path(self) -> str: def mask_french_alps(self):
assert self.model_name in ['Safran', 'Crocus'] resolution = AbstractMarginFunction.VISUALIZATION_RESOLUTION
study_folder = 'meteo' if self.model_name is 'Safran' else 'pro' mask_french_alps = np.zeros([resolution, resolution])
return op.join(self.full_path, self.REANALYSIS_FOLDER, study_folder) for polygon in self.idx_to_coords_list.values():
xy_values = list(zip(*polygon))
normalized_polygon = []
for values, (minlim, max_lim) in zip(xy_values, [self.visualization_x_limits, self.visualization_y_limits]):
values -= minlim
values *= resolution / (max_lim - minlim)
normalized_polygon.append(values)
normalized_polygon = list(zip(*normalized_polygon))
img = Image.new('L', (resolution, resolution), 0)
ImageDraw.Draw(img).polygon(normalized_polygon, outline=1, fill=1)
mask_massif = np.array(img)
mask_french_alps += mask_massif
return ~np.array(mask_french_alps, dtype=bool)
...@@ -67,7 +67,7 @@ if __name__ == '__main__': ...@@ -67,7 +67,7 @@ if __name__ == '__main__':
# print(study.all_massif_names) # print(study.all_massif_names)
# print(study.massif_name_to_altitudes) # print(study.massif_name_to_altitudes)
# print(study.year_to_daily_time_serie_array[1958].shape) # print(study.year_to_daily_time_serie_array[1958].shape)
print(study.missing_massif_name) # print(study.missing_massif_name)
# print(len(d.variables['time'])) # print(len(d.variables['time']))
# print(study.year_to_annual_total) # print(study.year_to_annual_total)
......
...@@ -749,9 +749,16 @@ class StudyVisualizer(object): ...@@ -749,9 +749,16 @@ class StudyVisualizer(object):
for massif_name in self.study.study_massif_names} for massif_name in self.study.study_massif_names}
return pd.DataFrame(massif_to_gev_mle, columns=self.study.study_massif_names) return pd.DataFrame(massif_to_gev_mle, columns=self.study.study_massif_names)
@property
def df_all_daily_time_series_concatenated(self) -> pd.DataFrame:
df_list = [pd.DataFrame(time_serie, columns=self.study.study_massif_names) for time_serie in
self.study.year_to_daily_time_serie_array.values()]
df_concatenated = pd.concat(df_list)
return df_concatenated
def df_gpd_mle(self, threshold) -> pd.DataFrame: def df_gpd_mle(self, threshold) -> pd.DataFrame:
# Fit a margin fit on each massif # Fit a margin fit on each massif
massif_to_gev_mle = {massif_name: GpdMleFit(self.study.df_all_daily_time_series_concatenated[massif_name], massif_to_gev_mle = {massif_name: GpdMleFit(self.df_all_daily_time_series_concatenated[massif_name],
threshold=threshold).gpd_params.summary_serie threshold=threshold).gpd_params.summary_serie
for massif_name in self.study.study_massif_names} for massif_name in self.study.study_massif_names}
return pd.DataFrame(massif_to_gev_mle, columns=self.study.study_massif_names) return pd.DataFrame(massif_to_gev_mle, columns=self.study.study_massif_names)
...@@ -32,7 +32,7 @@ class TestSCMAllStudy(unittest.TestCase): ...@@ -32,7 +32,7 @@ class TestSCMAllStudy(unittest.TestCase):
only_first_one=False, verbose=False, only_first_one=False, verbose=False,
altitudes=sample(set(ALL_ALTITUDES), k=nb_sample), nb_days=nb_days): altitudes=sample(set(ALL_ALTITUDES), k=nb_sample), nb_days=nb_days):
self.assertTrue('day' in study.variable_name) self.assertTrue('day' in study.variable_name)
first_path_file = study.ordered_years_and_path_files()[0][0] first_path_file = study.ordered_years_and_path_files[0][0]
variable_array = study.load_variables(path_file=first_path_file) variable_array = study.load_variables(path_file=first_path_file)
variable_object = study.instantiate_variable_object(variable_array) variable_object = study.instantiate_variable_object(variable_array)
self.assertEqual((365, 263), variable_object.daily_time_serie_array.shape, self.assertEqual((365, 263), variable_object.daily_time_serie_array.shape,
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment