From 745a2050cf2d39086a242dc9df7bb03f7001c941 Mon Sep 17 00:00:00 2001 From: Xylar Asay-Davis Date: Tue, 30 Jan 2018 10:11:15 -0700 Subject: [PATCH 01/71] Add util. script for making MPAS to lat/lon mapping files --- .../make_mpas_to_lat_lon_mapping.py | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100755 utility_scripts/make_mpas_to_lat_lon_mapping.py diff --git a/utility_scripts/make_mpas_to_lat_lon_mapping.py b/utility_scripts/make_mpas_to_lat_lon_mapping.py new file mode 100755 index 000000000..00d508356 --- /dev/null +++ b/utility_scripts/make_mpas_to_lat_lon_mapping.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python + +''' +Creates a mapping file that can be used with ncremap (NCO) to remap MPAS files +to a latitude/longitude grid. + +Usage: Copy this script into the main MPAS-Analysis directory (up one level). +Modify the grid name, the path to the MPAS grid file and the output grid +resolution. +''' + +from mpas_analysis.shared.interpolation import Remapper +from mpas_analysis.shared.grid import MpasMeshDescriptor +from mpas_analysis.shared.climatology import get_comparison_descriptor +from mpas_analysis.configuration import MpasAnalysisConfigParser + + +# replace with the MPAS mesh name +inGridName = 'oQU240' + +# replace with the path to the desired mesh or restart file +inGridFileName = '/media/xylar/extra_data/analysis/edison/G-QU240-master-intel/run/mpaso.rst.0001-01-06_00000.nc' + +config = MpasAnalysisConfigParser() +config.read('mpas_analysis/config.default') +# replace 1.0 with the desired resolution of the output mesh +config.set('climatology', 'comparisonLatResolution', '1.0') +config.set('climatology', 'comparisonLonResolution', '1.0') + +inDescriptor = MpasMeshDescriptor(inGridFileName, inGridName) + +outDescriptor = get_comparison_descriptor(config, 'latlon') +outGridName = outDescriptor.meshName + +mappingFileName = 'map_{}_to_{}.nc'.format(inGridName, outGridName) + +remapper = Remapper(inDescriptor, outDescriptor, mappingFileName) + +remapper.build_mapping_file(method='bilinear') From 4fb69cdcd8f37af484fce85e2136b7931b5f75fc Mon Sep 17 00:00:00 2001 From: Xylar Asay-Davis Date: Wed, 31 Jan 2018 11:42:19 -0700 Subject: [PATCH 02/71] Error if the requested config file(s) don't exist --- run_mpas_analysis | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/run_mpas_analysis b/run_mpas_analysis index 0472d9a1b..53d1de451 100755 --- a/run_mpas_analysis +++ b/run_mpas_analysis @@ -460,6 +460,10 @@ if __name__ == "__main__": type=str, nargs='*', help='config file') args = parser.parse_args() + for configFile in args.configFiles: + if not os.path.exists(configFile): + raise OSError('Config file {} not found.'.format(configFile)) + # add config.default to cover default not included in the config files # provided on the command line if pkg_resources.resource_exists('mpas_analysis', 'config.default'): From 9c5e01872046836e140415ba68ffc5fb9aec631f Mon Sep 17 00:00:00 2001 From: Xylar Asay-Davis Date: Wed, 31 Jan 2018 11:42:44 -0700 Subject: [PATCH 03/71] Plot the zero line across the full plot Before this merge, the zero line has the same extent as the first (valid) curve being plotted, whereas it should really have the full extent of the axis. (Thanks @vanroekel for finding this issue.) --- mpas_analysis/shared/plot/plotting.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/mpas_analysis/shared/plot/plotting.py b/mpas_analysis/shared/plot/plotting.py index eff883a41..bebeb6346 100644 --- a/mpas_analysis/shared/plot/plotting.py +++ b/mpas_analysis/shared/plot/plotting.py @@ -164,15 +164,14 @@ def timeseries_analysis_plot(config, dsvalues, N, title, xlabel, ylabel, 'color': config.get('plot', 'titleFontColor'), 'weight': config.get('plot', 'titleFontWeight')} + plot_xtick_format(plt, calendar, minDays, maxDays, maxXTicks) + # Add a y=0 line if y ranges between positive and negative values yaxLimits = ax.get_ylim() if yaxLimits[0]*yaxLimits[1] < 0: - indgood = np.where(np.logical_not(np.isnan(mean))) - x = mean['Time'][indgood] + x = ax.get_xlim() plt.plot(x, np.zeros(np.size(x)), 'k-', linewidth=1.2, zorder=1) - plot_xtick_format(plt, calendar, minDays, maxDays, maxXTicks) - if title is not None: plt.title(title, **title_font) if xlabel is not None: From 87ff9807e1112b4bea9cd71c31b84d9ff70f0058 Mon Sep 17 00:00:00 2001 From: Xylar Asay-Davis Date: Mon, 12 Feb 2018 12:26:48 -0700 Subject: [PATCH 04/71] Switch from relative to absolute imports This is the recommended python standard. --- mpas_analysis/analysis_task_template.py | 7 ++-- mpas_analysis/configuration/__init__.py | 3 +- mpas_analysis/ocean/__init__.py | 33 +++++++++++-------- .../ocean/climatology_map_antarctic_melt.py | 15 +++++---- mpas_analysis/ocean/climatology_map_mld.py | 13 ++++---- mpas_analysis/ocean/climatology_map_sose.py | 16 +++++---- mpas_analysis/ocean/climatology_map_sss.py | 11 ++++--- mpas_analysis/ocean/climatology_map_sst.py | 11 ++++--- .../ocean/compute_anomaly_subtask.py | 11 ++++--- mpas_analysis/ocean/index_nino34.py | 16 ++++----- .../ocean/meridional_heat_transport.py | 14 ++++---- .../ocean/plot_climatology_map_subtask.py | 11 ++++--- ...ot_depth_integrated_time_series_subtask.py | 17 +++++----- mpas_analysis/ocean/plot_hovmoller_subtask.py | 11 ++++--- .../ocean/remap_depth_slices_subtask.py | 6 ++-- mpas_analysis/ocean/streamfunction_moc.py | 15 +++++---- .../ocean/time_series_antarctic_melt.py | 13 ++++---- .../ocean/time_series_ohc_anomaly.py | 8 ++--- .../ocean/time_series_salinity_anomaly.py | 6 ++-- mpas_analysis/ocean/time_series_sst.py | 17 +++++----- .../ocean/time_series_temperature_anomaly.py | 6 ++-- mpas_analysis/sea_ice/__init__.py | 8 +++-- .../sea_ice/climatology_map_sea_ice_conc.py | 11 ++++--- .../sea_ice/climatology_map_sea_ice_thick.py | 11 ++++--- .../sea_ice/plot_climatology_map_subtask.py | 9 ++--- mpas_analysis/sea_ice/time_series.py | 23 ++++++------- mpas_analysis/shared/__init__.py | 2 +- mpas_analysis/shared/analysis_task.py | 5 +-- mpas_analysis/shared/climatology/__init__.py | 15 +++++---- .../shared/climatology/climatology.py | 21 +++++++----- .../climatology/comparison_descriptors.py | 5 +-- .../climatology/mpas_climatology_task.py | 5 +-- .../remap_mpas_climatology_subtask.py | 19 ++++++----- .../remap_observed_climatology_subtask.py | 16 +++++---- mpas_analysis/shared/containers.py | 6 ++-- .../shared/generalized_reader/__init__.py | 3 +- .../generalized_reader/generalized_reader.py | 5 +-- mpas_analysis/shared/grid/__init__.py | 4 +-- mpas_analysis/shared/html/__init__.py | 5 +-- mpas_analysis/shared/html/image_xml.py | 2 +- mpas_analysis/shared/html/pages.py | 2 +- .../shared/interpolation/__init__.py | 2 +- .../shared/interpolation/remapper.py | 4 +-- mpas_analysis/shared/io/__init__.py | 10 +++--- mpas_analysis/shared/io/mpas_reader.py | 3 +- .../shared/io/namelist_streams_interface.py | 6 ++-- .../shared/mpas_xarray/mpas_xarray.py | 5 +-- mpas_analysis/shared/plot/plotting.py | 5 +-- mpas_analysis/shared/time_series/__init__.py | 10 +++--- mpas_analysis/shared/time_series/anomaly.py | 4 +-- .../time_series/mpas_time_series_task.py | 7 ++-- .../shared/time_series/time_series.py | 2 +- mpas_analysis/shared/timekeeping/utility.py | 3 +- mpas_analysis/test/test_mpas_config_parser.py | 2 +- 54 files changed, 278 insertions(+), 222 deletions(-) diff --git a/mpas_analysis/analysis_task_template.py b/mpas_analysis/analysis_task_template.py index 2ec02f293..0c53f46e7 100644 --- a/mpas_analysis/analysis_task_template.py +++ b/mpas_analysis/analysis_task_template.py @@ -42,11 +42,12 @@ # import mpas_analysis module here (those with relative paths starting with # dots) -from ..shared.analysis_task import AnalysisTask +from mpas_analysis.shared.analysis_task import AnalysisTask -from ..shared.html import write_image_xml +from mpas_analysis.shared.html import write_image_xml -from ..shared.climatology import update_climatology_bounds_from_file_names +from mpas_analysis.shared.climatology import \ + update_climatology_bounds_from_file_names # Everywhere in this template, change MyTask to the name of your task, starting diff --git a/mpas_analysis/configuration/__init__.py b/mpas_analysis/configuration/__init__.py index 114e54cb5..644ae9562 100644 --- a/mpas_analysis/configuration/__init__.py +++ b/mpas_analysis/configuration/__init__.py @@ -1 +1,2 @@ -from .mpas_analysis_config_parser import MpasAnalysisConfigParser +from mpas_analysis.configuration.mpas_analysis_config_parser import \ + MpasAnalysisConfigParser diff --git a/mpas_analysis/ocean/__init__.py b/mpas_analysis/ocean/__init__.py index a9e4f9c89..2a8097a67 100644 --- a/mpas_analysis/ocean/__init__.py +++ b/mpas_analysis/ocean/__init__.py @@ -1,16 +1,21 @@ -from .climatology_map_sst import ClimatologyMapSST -from .climatology_map_mld import ClimatologyMapMLD -from .climatology_map_sss import ClimatologyMapSSS -from .climatology_map_antarctic_melt import ClimatologyMapAntarcticMelt -from .climatology_map_sose import ClimatologyMapSoseTemperature, \ - ClimatologyMapSoseSalinity +from mpas_analysis.ocean.climatology_map_sst import ClimatologyMapSST +from mpas_analysis.ocean.climatology_map_mld import ClimatologyMapMLD +from mpas_analysis.ocean.climatology_map_sss import ClimatologyMapSSS +from mpas_analysis.ocean.climatology_map_antarctic_melt import \ + ClimatologyMapAntarcticMelt +from mpas_analysis.ocean.climatology_map_sose import \ + ClimatologyMapSoseTemperature, ClimatologyMapSoseSalinity -from .time_series_temperature_anomaly import TimeSeriesTemperatureAnomaly -from .time_series_salinity_anomaly import TimeSeriesSalinityAnomaly -from .time_series_ohc_anomaly import TimeSeriesOHCAnomaly +from mpas_analysis.ocean.time_series_temperature_anomaly import \ + TimeSeriesTemperatureAnomaly +from mpas_analysis.ocean.time_series_salinity_anomaly import \ + TimeSeriesSalinityAnomaly +from mpas_analysis.ocean.time_series_ohc_anomaly import TimeSeriesOHCAnomaly -from .time_series_sst import TimeSeriesSST -from .index_nino34 import IndexNino34 -from .streamfunction_moc import StreamfunctionMOC -from .meridional_heat_transport import MeridionalHeatTransport -from .time_series_antarctic_melt import TimeSeriesAntarcticMelt +from mpas_analysis.ocean.time_series_sst import TimeSeriesSST +from mpas_analysis.ocean.index_nino34 import IndexNino34 +from mpas_analysis.ocean.streamfunction_moc import StreamfunctionMOC +from mpas_analysis.ocean.meridional_heat_transport import \ + MeridionalHeatTransport +from mpas_analysis.ocean.time_series_antarctic_melt import \ + TimeSeriesAntarcticMelt diff --git a/mpas_analysis/ocean/climatology_map_antarctic_melt.py b/mpas_analysis/ocean/climatology_map_antarctic_melt.py index 47e4a82af..07002cc73 100644 --- a/mpas_analysis/ocean/climatology_map_antarctic_melt.py +++ b/mpas_analysis/ocean/climatology_map_antarctic_melt.py @@ -3,20 +3,21 @@ import xarray as xr -from ..shared import AnalysisTask +from mpas_analysis.shared import AnalysisTask -from ..shared.io.utility import build_config_full_path +from mpas_analysis.shared.io.utility import build_config_full_path -from ..shared.climatology import RemapMpasClimatologySubtask, \ +from mpas_analysis.shared.climatology import RemapMpasClimatologySubtask, \ RemapObservedClimatologySubtask, get_antarctic_stereographic_projection -from .plot_climatology_map_subtask import PlotClimatologyMapSubtask +from mpas_analysis.ocean.plot_climatology_map_subtask import \ + PlotClimatologyMapSubtask -from ..shared.mpas_xarray import mpas_xarray +from mpas_analysis.shared.mpas_xarray import mpas_xarray -from ..shared.constants import constants +from mpas_analysis.shared.constants import constants -from ..shared.grid import ProjectionGridDescriptor +from mpas_analysis.shared.grid import ProjectionGridDescriptor class ClimatologyMapAntarcticMelt(AnalysisTask): # {{{ diff --git a/mpas_analysis/ocean/climatology_map_mld.py b/mpas_analysis/ocean/climatology_map_mld.py index 174f065a6..6631d2c8e 100644 --- a/mpas_analysis/ocean/climatology_map_mld.py +++ b/mpas_analysis/ocean/climatology_map_mld.py @@ -4,18 +4,19 @@ import xarray as xr import numpy as np -from ..shared import AnalysisTask +from mpas_analysis.shared import AnalysisTask -from ..shared.io.utility import build_config_full_path +from mpas_analysis.shared.io.utility import build_config_full_path -from ..shared.climatology import RemapMpasClimatologySubtask, \ +from mpas_analysis.shared.climatology import RemapMpasClimatologySubtask, \ RemapObservedClimatologySubtask -from .plot_climatology_map_subtask import PlotClimatologyMapSubtask +from mpas_analysis.ocean.plot_climatology_map_subtask import \ + PlotClimatologyMapSubtask -from ..shared.grid import LatLonGridDescriptor +from mpas_analysis.shared.grid import LatLonGridDescriptor -from ..shared.mpas_xarray import mpas_xarray +from mpas_analysis.shared.mpas_xarray import mpas_xarray class ClimatologyMapMLD(AnalysisTask): # {{{ diff --git a/mpas_analysis/ocean/climatology_map_sose.py b/mpas_analysis/ocean/climatology_map_sose.py index 894b8ebd6..ef23524ab 100644 --- a/mpas_analysis/ocean/climatology_map_sose.py +++ b/mpas_analysis/ocean/climatology_map_sose.py @@ -9,20 +9,22 @@ import xarray as xr -from ..shared import AnalysisTask +from mpas_analysis.shared import AnalysisTask -from .remap_depth_slices_subtask import RemapDepthSlicesSubtask +from mpas_analysis.ocean.remap_depth_slices_subtask import \ + RemapDepthSlicesSubtask -from .plot_climatology_map_subtask import PlotClimatologyMapSubtask +from mpas_analysis.ocean.plot_climatology_map_subtask import \ + PlotClimatologyMapSubtask -from ..shared.io.utility import build_config_full_path +from mpas_analysis.shared.io.utility import build_config_full_path -from ..shared.climatology import RemapObservedClimatologySubtask, \ +from mpas_analysis.shared.climatology import RemapObservedClimatologySubtask, \ get_antarctic_stereographic_projection -from ..shared.grid import ProjectionGridDescriptor +from mpas_analysis.shared.grid import ProjectionGridDescriptor -from ..shared.mpas_xarray import mpas_xarray +from mpas_analysis.shared.mpas_xarray import mpas_xarray class ClimatologyMapSoseTemperature(AnalysisTask): # {{{ diff --git a/mpas_analysis/ocean/climatology_map_sss.py b/mpas_analysis/ocean/climatology_map_sss.py index 0fdc0877d..7e8f27a55 100644 --- a/mpas_analysis/ocean/climatology_map_sss.py +++ b/mpas_analysis/ocean/climatology_map_sss.py @@ -4,16 +4,17 @@ import xarray as xr import datetime -from ..shared import AnalysisTask +from mpas_analysis.shared import AnalysisTask -from ..shared.io.utility import build_config_full_path +from mpas_analysis.shared.io.utility import build_config_full_path -from ..shared.climatology import RemapMpasClimatologySubtask, \ +from mpas_analysis.shared.climatology import RemapMpasClimatologySubtask, \ RemapObservedClimatologySubtask -from .plot_climatology_map_subtask import PlotClimatologyMapSubtask +from mpas_analysis.ocean.plot_climatology_map_subtask import \ + PlotClimatologyMapSubtask -from ..shared.grid import LatLonGridDescriptor +from mpas_analysis.shared.grid import LatLonGridDescriptor class ClimatologyMapSSS(AnalysisTask): # {{{ diff --git a/mpas_analysis/ocean/climatology_map_sst.py b/mpas_analysis/ocean/climatology_map_sst.py index 0a5b1d699..b7c99a8f5 100644 --- a/mpas_analysis/ocean/climatology_map_sst.py +++ b/mpas_analysis/ocean/climatology_map_sst.py @@ -4,16 +4,17 @@ import xarray as xr import datetime -from ..shared import AnalysisTask +from mpas_analysis.shared import AnalysisTask -from ..shared.io.utility import build_config_full_path +from mpas_analysis.shared.io.utility import build_config_full_path -from ..shared.climatology import RemapMpasClimatologySubtask, \ +from mpas_analysis.shared.climatology import RemapMpasClimatologySubtask, \ RemapObservedClimatologySubtask -from .plot_climatology_map_subtask import PlotClimatologyMapSubtask +from mpas_analysis.ocean.plot_climatology_map_subtask import \ + PlotClimatologyMapSubtask -from ..shared.grid import LatLonGridDescriptor +from mpas_analysis.shared.grid import LatLonGridDescriptor class ClimatologyMapSST(AnalysisTask): # {{{ diff --git a/mpas_analysis/ocean/compute_anomaly_subtask.py b/mpas_analysis/ocean/compute_anomaly_subtask.py index befefbf8c..49773a538 100644 --- a/mpas_analysis/ocean/compute_anomaly_subtask.py +++ b/mpas_analysis/ocean/compute_anomaly_subtask.py @@ -5,15 +5,16 @@ import os -from ..shared import AnalysisTask +from mpas_analysis.shared import AnalysisTask -from ..shared.io import write_netcdf +from mpas_analysis.shared.io import write_netcdf -from ..shared.timekeeping.utility import get_simulation_start_time +from mpas_analysis.shared.timekeeping.utility import get_simulation_start_time -from ..shared.io.utility import build_config_full_path +from mpas_analysis.shared.io.utility import build_config_full_path -from ..shared.time_series import compute_moving_avg_anomaly_from_start +from mpas_analysis.shared.time_series import \ + compute_moving_avg_anomaly_from_start class ComputeAnomalySubtask(AnalysisTask): diff --git a/mpas_analysis/ocean/index_nino34.py b/mpas_analysis/ocean/index_nino34.py index 608621328..105342af2 100644 --- a/mpas_analysis/ocean/index_nino34.py +++ b/mpas_analysis/ocean/index_nino34.py @@ -10,19 +10,19 @@ from scipy import signal, stats import matplotlib.pyplot as plt -from ..shared.climatology import climatology -from ..shared.constants import constants -from ..shared.io.utility import build_config_full_path +from mpas_analysis.shared.climatology import climatology +from mpas_analysis.shared.constants import constants +from mpas_analysis.shared.io.utility import build_config_full_path -from ..shared.timekeeping.utility import datetime_to_days, \ +from mpas_analysis.shared.timekeeping.utility import datetime_to_days, \ string_to_days_since_date -from ..shared.io import open_mpas_dataset +from mpas_analysis.shared.io import open_mpas_dataset -from ..shared.plot.plotting import plot_xtick_format +from mpas_analysis.shared.plot.plotting import plot_xtick_format -from ..shared import AnalysisTask -from ..shared.html import write_image_xml +from mpas_analysis.shared import AnalysisTask +from mpas_analysis.shared.html import write_image_xml class IndexNino34(AnalysisTask): # {{{ diff --git a/mpas_analysis/ocean/meridional_heat_transport.py b/mpas_analysis/ocean/meridional_heat_transport.py index e6b139e76..f1dbfd0fc 100644 --- a/mpas_analysis/ocean/meridional_heat_transport.py +++ b/mpas_analysis/ocean/meridional_heat_transport.py @@ -6,16 +6,18 @@ import numpy as np import os -from ..shared.plot.plotting import plot_vertical_section,\ +from mpas_analysis.shared.plot.plotting import plot_vertical_section,\ setup_colormap, plot_1D -from ..shared.io.utility import build_config_full_path, make_directories -from ..shared.io import write_netcdf, subset_variables +from mpas_analysis.shared.io.utility import build_config_full_path, \ + make_directories +from mpas_analysis.shared.io import write_netcdf, subset_variables -from ..shared import AnalysisTask -from ..shared.html import write_image_xml +from mpas_analysis.shared import AnalysisTask +from mpas_analysis.shared.html import write_image_xml -from ..shared.climatology import get_unmasked_mpas_climatology_file_name +from mpas_analysis.shared.climatology import \ + get_unmasked_mpas_climatology_file_name class MeridionalHeatTransport(AnalysisTask): # {{{ diff --git a/mpas_analysis/ocean/plot_climatology_map_subtask.py b/mpas_analysis/ocean/plot_climatology_map_subtask.py index 826046a0f..34b11d39d 100644 --- a/mpas_analysis/ocean/plot_climatology_map_subtask.py +++ b/mpas_analysis/ocean/plot_climatology_map_subtask.py @@ -13,16 +13,17 @@ import xarray as xr import numpy as np -from ..shared import AnalysisTask +from mpas_analysis.shared import AnalysisTask -from ..shared.plot.plotting import plot_global_comparison, \ +from mpas_analysis.shared.plot.plotting import plot_global_comparison, \ setup_colormap, plot_polar_projection_comparison -from ..shared.html import write_image_xml +from mpas_analysis.shared.html import write_image_xml -from ..shared.grid import interp_extrap_corner +from mpas_analysis.shared.grid import interp_extrap_corner -from ..shared.climatology import get_remapped_mpas_climatology_file_name +from mpas_analysis.shared.climatology import \ + get_remapped_mpas_climatology_file_name def nans_to_numpy_mask(field): diff --git a/mpas_analysis/ocean/plot_depth_integrated_time_series_subtask.py b/mpas_analysis/ocean/plot_depth_integrated_time_series_subtask.py index 10f3b1bf2..ad98cd56c 100644 --- a/mpas_analysis/ocean/plot_depth_integrated_time_series_subtask.py +++ b/mpas_analysis/ocean/plot_depth_integrated_time_series_subtask.py @@ -6,20 +6,21 @@ import xarray as xr import os -from ..shared import AnalysisTask +from mpas_analysis.shared import AnalysisTask -from ..shared.plot.plotting import timeseries_analysis_plot +from mpas_analysis.shared.plot.plotting import timeseries_analysis_plot -from ..shared.generalized_reader import open_multifile_dataset -from ..shared.io import open_mpas_dataset +from mpas_analysis.shared.generalized_reader import open_multifile_dataset +from mpas_analysis.shared.io import open_mpas_dataset -from ..shared.timekeeping.utility import date_to_days, days_to_datetime +from mpas_analysis.shared.timekeeping.utility import date_to_days, \ + days_to_datetime -from ..shared.io.utility import build_config_full_path +from mpas_analysis.shared.io.utility import build_config_full_path -from ..shared.html import write_image_xml +from mpas_analysis.shared.html import write_image_xml -from ..shared.time_series import compute_moving_avg +from mpas_analysis.shared.time_series import compute_moving_avg class PlotDepthIntegratedTimeSeriesSubtask(AnalysisTask): diff --git a/mpas_analysis/ocean/plot_hovmoller_subtask.py b/mpas_analysis/ocean/plot_hovmoller_subtask.py index 2c802c8d7..96e54a284 100644 --- a/mpas_analysis/ocean/plot_hovmoller_subtask.py +++ b/mpas_analysis/ocean/plot_hovmoller_subtask.py @@ -6,15 +6,16 @@ import xarray as xr import os -from ..shared import AnalysisTask +from mpas_analysis.shared import AnalysisTask -from ..shared.plot.plotting import plot_vertical_section, setup_colormap +from mpas_analysis.shared.plot.plotting import plot_vertical_section, \ + setup_colormap -from ..shared.io import open_mpas_dataset +from mpas_analysis.shared.io import open_mpas_dataset -from ..shared.io.utility import build_config_full_path +from mpas_analysis.shared.io.utility import build_config_full_path -from ..shared.html import write_image_xml +from mpas_analysis.shared.html import write_image_xml class PlotHovmollerSubtask(AnalysisTask): diff --git a/mpas_analysis/ocean/remap_depth_slices_subtask.py b/mpas_analysis/ocean/remap_depth_slices_subtask.py index 6788fe43e..b2102ae59 100644 --- a/mpas_analysis/ocean/remap_depth_slices_subtask.py +++ b/mpas_analysis/ocean/remap_depth_slices_subtask.py @@ -4,11 +4,11 @@ import xarray as xr import numpy as np -from ..shared.climatology import RemapMpasClimatologySubtask +from mpas_analysis.shared.climatology import RemapMpasClimatologySubtask -from ..shared.mpas_xarray import mpas_xarray +from mpas_analysis.shared.mpas_xarray import mpas_xarray -from .utility import compute_zmid +from mpas_analysis.ocean.utility import compute_zmid class RemapDepthSlicesSubtask(RemapMpasClimatologySubtask): # {{{ diff --git a/mpas_analysis/ocean/streamfunction_moc.py b/mpas_analysis/ocean/streamfunction_moc.py index 974b32845..04c9d8a3a 100644 --- a/mpas_analysis/ocean/streamfunction_moc.py +++ b/mpas_analysis/ocean/streamfunction_moc.py @@ -8,19 +8,20 @@ import netCDF4 import os -from ..shared.constants.constants import m3ps_to_Sv -from ..shared.plot.plotting import plot_vertical_section,\ +from mpas_analysis.shared.constants.constants import m3ps_to_Sv +from mpas_analysis.shared.plot.plotting import plot_vertical_section,\ timeseries_analysis_plot, setup_colormap -from ..shared.io.utility import build_config_full_path, make_directories +from mpas_analysis.shared.io.utility import build_config_full_path, \ + make_directories -from ..shared.io import open_mpas_dataset +from mpas_analysis.shared.io import open_mpas_dataset -from ..shared.timekeeping.utility import days_to_datetime +from mpas_analysis.shared.timekeeping.utility import days_to_datetime -from ..shared import AnalysisTask +from mpas_analysis.shared import AnalysisTask -from ..shared.html import write_image_xml +from mpas_analysis.shared.html import write_image_xml class StreamfunctionMOC(AnalysisTask): # {{{ diff --git a/mpas_analysis/ocean/time_series_antarctic_melt.py b/mpas_analysis/ocean/time_series_antarctic_melt.py index 8c668826b..743da8af3 100644 --- a/mpas_analysis/ocean/time_series_antarctic_melt.py +++ b/mpas_analysis/ocean/time_series_antarctic_melt.py @@ -5,17 +5,18 @@ import xarray import numpy -from ..shared.analysis_task import AnalysisTask +from mpas_analysis.shared.analysis_task import AnalysisTask -from ..shared.constants import constants +from mpas_analysis.shared.constants import constants -from ..shared.plot.plotting import timeseries_analysis_plot +from mpas_analysis.shared.plot.plotting import timeseries_analysis_plot -from ..shared.io import open_mpas_dataset, write_netcdf +from mpas_analysis.shared.io import open_mpas_dataset, write_netcdf -from ..shared.io.utility import build_config_full_path, make_directories +from mpas_analysis.shared.io.utility import build_config_full_path, \ + make_directories -from ..shared.html import write_image_xml +from mpas_analysis.shared.html import write_image_xml import csv diff --git a/mpas_analysis/ocean/time_series_ohc_anomaly.py b/mpas_analysis/ocean/time_series_ohc_anomaly.py index 0592abaf5..00d6e3594 100644 --- a/mpas_analysis/ocean/time_series_ohc_anomaly.py +++ b/mpas_analysis/ocean/time_series_ohc_anomaly.py @@ -5,11 +5,11 @@ import xarray as xr -from ..shared import AnalysisTask +from mpas_analysis.shared import AnalysisTask -from .compute_anomaly_subtask import ComputeAnomalySubtask -from .plot_hovmoller_subtask import PlotHovmollerSubtask -from .plot_depth_integrated_time_series_subtask import \ +from mpas_analysis.ocean.compute_anomaly_subtask import ComputeAnomalySubtask +from mpas_analysis.ocean.plot_hovmoller_subtask import PlotHovmollerSubtask +from mpas_analysis.ocean.plot_depth_integrated_time_series_subtask import \ PlotDepthIntegratedTimeSeriesSubtask diff --git a/mpas_analysis/ocean/time_series_salinity_anomaly.py b/mpas_analysis/ocean/time_series_salinity_anomaly.py index dba021329..3f29492b3 100644 --- a/mpas_analysis/ocean/time_series_salinity_anomaly.py +++ b/mpas_analysis/ocean/time_series_salinity_anomaly.py @@ -3,10 +3,10 @@ from __future__ import absolute_import, division, print_function, \ unicode_literals -from ..shared import AnalysisTask +from mpas_analysis.shared import AnalysisTask -from .compute_anomaly_subtask import ComputeAnomalySubtask -from .plot_hovmoller_subtask import PlotHovmollerSubtask +from mpas_analysis.ocean.compute_anomaly_subtask import ComputeAnomalySubtask +from mpas_analysis.ocean.plot_hovmoller_subtask import PlotHovmollerSubtask class TimeSeriesSalinityAnomaly(AnalysisTask): diff --git a/mpas_analysis/ocean/time_series_sst.py b/mpas_analysis/ocean/time_series_sst.py index 947d2b881..9b889288d 100644 --- a/mpas_analysis/ocean/time_series_sst.py +++ b/mpas_analysis/ocean/time_series_sst.py @@ -2,18 +2,19 @@ from __future__ import absolute_import, division, print_function, \ unicode_literals -from ..shared import AnalysisTask +from mpas_analysis.shared import AnalysisTask -from ..shared.plot.plotting import timeseries_analysis_plot +from mpas_analysis.shared.plot.plotting import timeseries_analysis_plot -from ..shared.generalized_reader import open_multifile_dataset -from ..shared.io import open_mpas_dataset +from mpas_analysis.shared.generalized_reader import open_multifile_dataset +from mpas_analysis.shared.io import open_mpas_dataset -from ..shared.timekeeping.utility import date_to_days, days_to_datetime +from mpas_analysis.shared.timekeeping.utility import date_to_days, \ + days_to_datetime -from ..shared.io.utility import build_config_full_path, make_directories, \ - check_path_exists -from ..shared.html import write_image_xml +from mpas_analysis.shared.io.utility import build_config_full_path, \ + make_directories, check_path_exists +from mpas_analysis.shared.html import write_image_xml class TimeSeriesSST(AnalysisTask): diff --git a/mpas_analysis/ocean/time_series_temperature_anomaly.py b/mpas_analysis/ocean/time_series_temperature_anomaly.py index 4897795f3..9e61b2156 100644 --- a/mpas_analysis/ocean/time_series_temperature_anomaly.py +++ b/mpas_analysis/ocean/time_series_temperature_anomaly.py @@ -3,10 +3,10 @@ from __future__ import absolute_import, division, print_function, \ unicode_literals -from ..shared import AnalysisTask +from mpas_analysis.shared import AnalysisTask -from .compute_anomaly_subtask import ComputeAnomalySubtask -from .plot_hovmoller_subtask import PlotHovmollerSubtask +from mpas_analysis.ocean.compute_anomaly_subtask import ComputeAnomalySubtask +from mpas_analysis.ocean.plot_hovmoller_subtask import PlotHovmollerSubtask class TimeSeriesTemperatureAnomaly(AnalysisTask): diff --git a/mpas_analysis/sea_ice/__init__.py b/mpas_analysis/sea_ice/__init__.py index bc745d9d9..7f6a548b6 100644 --- a/mpas_analysis/sea_ice/__init__.py +++ b/mpas_analysis/sea_ice/__init__.py @@ -1,3 +1,5 @@ -from .climatology_map_sea_ice_conc import ClimatologyMapSeaIceConc -from .climatology_map_sea_ice_thick import ClimatologyMapSeaIceThick -from .time_series import TimeSeriesSeaIce +from mpas_analysis.sea_ice.climatology_map_sea_ice_conc import \ + ClimatologyMapSeaIceConc +from mpas_analysis.sea_ice.climatology_map_sea_ice_thick import \ + ClimatologyMapSeaIceThick +from mpas_analysis.sea_ice.time_series import TimeSeriesSeaIce diff --git a/mpas_analysis/sea_ice/climatology_map_sea_ice_conc.py b/mpas_analysis/sea_ice/climatology_map_sea_ice_conc.py index c749f5c9c..b1909dec0 100644 --- a/mpas_analysis/sea_ice/climatology_map_sea_ice_conc.py +++ b/mpas_analysis/sea_ice/climatology_map_sea_ice_conc.py @@ -4,16 +4,17 @@ import xarray as xr -from ..shared import AnalysisTask +from mpas_analysis.shared import AnalysisTask -from ..shared.climatology import RemapMpasClimatologySubtask, \ +from mpas_analysis.shared.climatology import RemapMpasClimatologySubtask, \ RemapObservedClimatologySubtask -from .plot_climatology_map_subtask import PlotClimatologyMapSubtask +from mpas_analysis.sea_ice.plot_climatology_map_subtask import \ + PlotClimatologyMapSubtask -from ..shared.io.utility import build_config_full_path +from mpas_analysis.shared.io.utility import build_config_full_path -from ..shared.grid import LatLonGridDescriptor +from mpas_analysis.shared.grid import LatLonGridDescriptor class ClimatologyMapSeaIceConc(AnalysisTask): # {{{ diff --git a/mpas_analysis/sea_ice/climatology_map_sea_ice_thick.py b/mpas_analysis/sea_ice/climatology_map_sea_ice_thick.py index 96c3f4f04..957b15830 100644 --- a/mpas_analysis/sea_ice/climatology_map_sea_ice_thick.py +++ b/mpas_analysis/sea_ice/climatology_map_sea_ice_thick.py @@ -4,16 +4,17 @@ import xarray as xr -from ..shared import AnalysisTask +from mpas_analysis.shared import AnalysisTask -from ..shared.climatology import RemapMpasClimatologySubtask, \ +from mpas_analysis.shared.climatology import RemapMpasClimatologySubtask, \ RemapObservedClimatologySubtask -from .plot_climatology_map_subtask import PlotClimatologyMapSubtask +from mpas_analysis.sea_ice.plot_climatology_map_subtask import \ + PlotClimatologyMapSubtask -from ..shared.io.utility import build_config_full_path +from mpas_analysis.shared.io.utility import build_config_full_path -from ..shared.grid import LatLonGridDescriptor +from mpas_analysis.shared.grid import LatLonGridDescriptor class ClimatologyMapSeaIceThick(AnalysisTask): # {{{ diff --git a/mpas_analysis/sea_ice/plot_climatology_map_subtask.py b/mpas_analysis/sea_ice/plot_climatology_map_subtask.py index 9d5bf9ad2..5ca70ff2e 100644 --- a/mpas_analysis/sea_ice/plot_climatology_map_subtask.py +++ b/mpas_analysis/sea_ice/plot_climatology_map_subtask.py @@ -7,14 +7,15 @@ import xarray as xr -from ..shared import AnalysisTask +from mpas_analysis.shared import AnalysisTask -from ..shared.plot.plotting import plot_polar_comparison, \ +from mpas_analysis.shared.plot.plotting import plot_polar_comparison, \ setup_colormap -from ..shared.html import write_image_xml +from mpas_analysis.shared.html import write_image_xml -from ..shared.climatology import get_remapped_mpas_climatology_file_name +from mpas_analysis.shared.climatology import \ + get_remapped_mpas_climatology_file_name class PlotClimatologyMapSubtask(AnalysisTask): # {{{ diff --git a/mpas_analysis/sea_ice/time_series.py b/mpas_analysis/sea_ice/time_series.py index c890964f3..67d34915b 100644 --- a/mpas_analysis/sea_ice/time_series.py +++ b/mpas_analysis/sea_ice/time_series.py @@ -5,23 +5,24 @@ import xarray as xr import os -from ..shared import AnalysisTask +from mpas_analysis.shared import AnalysisTask -from ..shared.plot.plotting import timeseries_analysis_plot, \ +from mpas_analysis.shared.plot.plotting import timeseries_analysis_plot, \ timeseries_analysis_plot_polar -from ..shared.io.utility import build_config_full_path, check_path_exists, \ - make_directories +from mpas_analysis.shared.io.utility import build_config_full_path, \ + check_path_exists, make_directories -from ..shared.timekeeping.utility import date_to_days, days_to_datetime, \ - datetime_to_days, get_simulation_start_time -from ..shared.timekeeping.MpasRelativeDelta import MpasRelativeDelta +from mpas_analysis.shared.timekeeping.utility import date_to_days, \ + days_to_datetime, datetime_to_days, get_simulation_start_time +from mpas_analysis.shared.timekeeping.MpasRelativeDelta import \ + MpasRelativeDelta -from ..shared.generalized_reader import open_multifile_dataset -from ..shared.io import open_mpas_dataset, write_netcdf -from ..shared.mpas_xarray.mpas_xarray import subset_variables +from mpas_analysis.shared.generalized_reader import open_multifile_dataset +from mpas_analysis.shared.io import open_mpas_dataset, write_netcdf +from mpas_analysis.shared.mpas_xarray.mpas_xarray import subset_variables -from ..shared.html import write_image_xml +from mpas_analysis.shared.html import write_image_xml class TimeSeriesSeaIce(AnalysisTask): diff --git a/mpas_analysis/shared/__init__.py b/mpas_analysis/shared/__init__.py index 27d9310c9..d6b130b6c 100644 --- a/mpas_analysis/shared/__init__.py +++ b/mpas_analysis/shared/__init__.py @@ -1 +1 @@ -from .analysis_task import AnalysisTask +from mpas_analysis.shared.analysis_task import AnalysisTask diff --git a/mpas_analysis/shared/analysis_task.py b/mpas_analysis/shared/analysis_task.py index f03625ecd..2e7b7d70b 100644 --- a/mpas_analysis/shared/analysis_task.py +++ b/mpas_analysis/shared/analysis_task.py @@ -16,8 +16,9 @@ import logging import sys -from .io import NameList, StreamsFile -from .io.utility import build_config_full_path, make_directories +from mpas_analysis.shared.io import NameList, StreamsFile +from mpas_analysis.shared.io.utility import build_config_full_path, \ + make_directories class AnalysisTask(Process): # {{{ diff --git a/mpas_analysis/shared/climatology/__init__.py b/mpas_analysis/shared/climatology/__init__.py index 3be6e13d9..afb8d7b4b 100644 --- a/mpas_analysis/shared/climatology/__init__.py +++ b/mpas_analysis/shared/climatology/__init__.py @@ -1,4 +1,4 @@ -from .climatology import get_remapper, \ +from mpas_analysis.shared.climatology.climatology import get_remapper, \ compute_monthly_climatology, compute_climatology, \ add_years_months_days_in_month, remap_and_write_climatology, \ get_unmasked_mpas_climatology_directory, \ @@ -6,8 +6,11 @@ get_masked_mpas_climatology_file_name, \ get_remapped_mpas_climatology_file_name -from .mpas_climatology_task import MpasClimatologyTask -from .remap_mpas_climatology_subtask import RemapMpasClimatologySubtask -from .remap_observed_climatology_subtask import RemapObservedClimatologySubtask -from .comparison_descriptors import get_comparison_descriptor, \ - get_antarctic_stereographic_projection +from mpas_analysis.shared.climatology.mpas_climatology_task import \ + MpasClimatologyTask +from mpas_analysis.shared.climatology.remap_mpas_climatology_subtask import \ + RemapMpasClimatologySubtask +from mpas_analysis.shared.climatology.remap_observed_climatology_subtask \ + import RemapObservedClimatologySubtask +from mpas_analysis.shared.climatology.comparison_descriptors import \ + get_comparison_descriptor, get_antarctic_stereographic_projection diff --git a/mpas_analysis/shared/climatology/climatology.py b/mpas_analysis/shared/climatology/climatology.py index a33469422..c2b411465 100644 --- a/mpas_analysis/shared/climatology/climatology.py +++ b/mpas_analysis/shared/climatology/climatology.py @@ -13,17 +13,19 @@ import os import numpy -from ..constants import constants +from mpas_analysis.shared.constants import constants -from ..timekeeping.utility import days_to_datetime +from mpas_analysis.shared.timekeeping.utility import days_to_datetime -from ..io.utility import build_config_full_path, make_directories, \ - fingerprint_generator -from ..io import write_netcdf +from mpas_analysis.shared.io.utility import build_config_full_path, \ + make_directories, fingerprint_generator +from mpas_analysis.shared.io import write_netcdf -from ..interpolation import Remapper -from ..grid import LatLonGridDescriptor, ProjectionGridDescriptor -from .comparison_descriptors import get_comparison_descriptor +from mpas_analysis.shared.interpolation import Remapper +from mpas_analysis.shared.grid import LatLonGridDescriptor, \ + ProjectionGridDescriptor +from mpas_analysis.shared.climatology.comparison_descriptors import \ + get_comparison_descriptor def get_remapper(config, sourceDescriptor, comparisonDescriptor, @@ -327,7 +329,8 @@ def remap_and_write_climatology(config, climatologyDataSet, useNcremap = config.getboolean('climatology', 'useNcremap') if (isinstance(remapper.sourceDescriptor, ProjectionGridDescriptor) or - isinstance(remapper.destinationDescriptor, ProjectionGridDescriptor)): + isinstance(remapper.destinationDescriptor, + ProjectionGridDescriptor)): # ncremap doesn't support projection grids useNcremap = False diff --git a/mpas_analysis/shared/climatology/comparison_descriptors.py b/mpas_analysis/shared/climatology/comparison_descriptors.py index 1c91c7476..ed553070f 100644 --- a/mpas_analysis/shared/climatology/comparison_descriptors.py +++ b/mpas_analysis/shared/climatology/comparison_descriptors.py @@ -12,9 +12,10 @@ import numpy import pyproj -from ..constants import constants +from mpas_analysis.shared.constants import constants -from ..grid import LatLonGridDescriptor, ProjectionGridDescriptor +from mpas_analysis.shared.grid import LatLonGridDescriptor, \ + ProjectionGridDescriptor def get_comparison_descriptor(config, comparisonGridName): # {{{ diff --git a/mpas_analysis/shared/climatology/mpas_climatology_task.py b/mpas_analysis/shared/climatology/mpas_climatology_task.py index fa5d05824..231bf3203 100644 --- a/mpas_analysis/shared/climatology/mpas_climatology_task.py +++ b/mpas_analysis/shared/climatology/mpas_climatology_task.py @@ -7,9 +7,10 @@ import subprocess from distutils.spawn import find_executable -from ..analysis_task import AnalysisTask +from mpas_analysis.shared.analysis_task import AnalysisTask -from .climatology import get_unmasked_mpas_climatology_directory, \ +from mpas_analysis.shared.climatology.climatology import \ + get_unmasked_mpas_climatology_directory, \ get_unmasked_mpas_climatology_file_name diff --git a/mpas_analysis/shared/climatology/remap_mpas_climatology_subtask.py b/mpas_analysis/shared/climatology/remap_mpas_climatology_subtask.py index 3e9d55067..771e97649 100644 --- a/mpas_analysis/shared/climatology/remap_mpas_climatology_subtask.py +++ b/mpas_analysis/shared/climatology/remap_mpas_climatology_subtask.py @@ -6,20 +6,23 @@ import numpy import os -from ..analysis_task import AnalysisTask +from mpas_analysis.shared.analysis_task import AnalysisTask -from ..constants import constants +from mpas_analysis.shared.constants import constants -from ..io.utility import build_config_full_path, make_directories -from ..io import write_netcdf +from mpas_analysis.shared.io.utility import build_config_full_path, \ + make_directories +from mpas_analysis.shared.io import write_netcdf -from .climatology import get_remapper, get_masked_mpas_climatology_file_name, \ +from mpas_analysis.shared.climatology.climatology import get_remapper, \ + get_masked_mpas_climatology_file_name, \ get_remapped_mpas_climatology_file_name -from .comparison_descriptors import get_comparison_descriptor +from mpas_analysis.shared.climatology.comparison_descriptors import \ + get_comparison_descriptor -from ..grid import MpasMeshDescriptor +from mpas_analysis.shared.grid import MpasMeshDescriptor -from ..mpas_xarray import mpas_xarray +from mpas_analysis.shared.mpas_xarray import mpas_xarray class RemapMpasClimatologySubtask(AnalysisTask): # {{{ diff --git a/mpas_analysis/shared/climatology/remap_observed_climatology_subtask.py b/mpas_analysis/shared/climatology/remap_observed_climatology_subtask.py index ac4c14af6..ba39e3cbf 100644 --- a/mpas_analysis/shared/climatology/remap_observed_climatology_subtask.py +++ b/mpas_analysis/shared/climatology/remap_observed_climatology_subtask.py @@ -5,17 +5,19 @@ import os.path import xarray as xr -from ..analysis_task import AnalysisTask +from mpas_analysis.shared.analysis_task import AnalysisTask -from ..constants import constants +from mpas_analysis.shared.constants import constants -from ..io.utility import build_config_full_path, make_directories -from ..io import write_netcdf +from mpas_analysis.shared.io.utility import build_config_full_path, \ + make_directories +from mpas_analysis.shared.io import write_netcdf -from .climatology import get_remapper, remap_and_write_climatology, \ - compute_climatology +from mpas_analysis.shared.climatology.climatology import get_remapper, \ + remap_and_write_climatology, compute_climatology -from .comparison_descriptors import get_comparison_descriptor +from mpas_analysis.shared.climatology.comparison_descriptors import \ + get_comparison_descriptor class RemapObservedClimatologySubtask(AnalysisTask): # {{{ diff --git a/mpas_analysis/shared/containers.py b/mpas_analysis/shared/containers.py index a0b30f004..8c2583a85 100644 --- a/mpas_analysis/shared/containers.py +++ b/mpas_analysis/shared/containers.py @@ -10,7 +10,9 @@ unicode_literals import collections -class ReadOnlyDict(collections.Mapping): #{{{ + + +class ReadOnlyDict(collections.Mapping): # {{{ """ Read only-dictionary http://stackoverflow.com/questions/19022868/how-to-make-dictionary-read-only-in-python 310/22/2016 @@ -28,6 +30,6 @@ def __len__(self): def __iter__(self): return iter(self._data) -#}}} +# }}} # vim: foldmethod=marker ai ts=4 sts=4 et sw=4 ft=python diff --git a/mpas_analysis/shared/generalized_reader/__init__.py b/mpas_analysis/shared/generalized_reader/__init__.py index 6db020e3b..4e5b85ce4 100644 --- a/mpas_analysis/shared/generalized_reader/__init__.py +++ b/mpas_analysis/shared/generalized_reader/__init__.py @@ -1 +1,2 @@ -from .generalized_reader import open_multifile_dataset \ No newline at end of file +from mpas_analysis.shared.generalized_reader.generalized_reader import \ + open_multifile_dataset diff --git a/mpas_analysis/shared/generalized_reader/generalized_reader.py b/mpas_analysis/shared/generalized_reader/generalized_reader.py index a7c1c4375..87b357baa 100644 --- a/mpas_analysis/shared/generalized_reader/generalized_reader.py +++ b/mpas_analysis/shared/generalized_reader/generalized_reader.py @@ -21,8 +21,9 @@ from functools import partial import resource -from ..mpas_xarray import mpas_xarray -from ..timekeeping.utility import string_to_days_since_date, days_to_datetime +from mpas_analysis.shared.mpas_xarray import mpas_xarray +from mpas_analysis.shared.timekeeping.utility import \ + string_to_days_since_date, days_to_datetime def open_multifile_dataset(fileNames, calendar, config, diff --git a/mpas_analysis/shared/grid/__init__.py b/mpas_analysis/shared/grid/__init__.py index beffc841f..4155437f5 100644 --- a/mpas_analysis/shared/grid/__init__.py +++ b/mpas_analysis/shared/grid/__init__.py @@ -1,2 +1,2 @@ -from .grid import MpasMeshDescriptor, LatLonGridDescriptor, \ - ProjectionGridDescriptor, interp_extrap_corner +from mpas_analysis.shared.grid.grid import MpasMeshDescriptor, \ + LatLonGridDescriptor, ProjectionGridDescriptor, interp_extrap_corner diff --git a/mpas_analysis/shared/html/__init__.py b/mpas_analysis/shared/html/__init__.py index 209d380a7..85962d2ac 100644 --- a/mpas_analysis/shared/html/__init__.py +++ b/mpas_analysis/shared/html/__init__.py @@ -1,2 +1,3 @@ -from .pages import MainPage, ComponentPage, generate_html -from .image_xml import write_image_xml +from mpas_analysis.shared.html.pages import MainPage, ComponentPage, \ + generate_html +from mpas_analysis.shared.html.image_xml import write_image_xml diff --git a/mpas_analysis/shared/html/image_xml.py b/mpas_analysis/shared/html/image_xml.py index 001e62602..a05a8c2f4 100644 --- a/mpas_analysis/shared/html/image_xml.py +++ b/mpas_analysis/shared/html/image_xml.py @@ -11,7 +11,7 @@ from lxml import etree from PIL import Image -from ..io.utility import build_config_full_path +from mpas_analysis.shared.io.utility import build_config_full_path def write_image_xml(config, filePrefix, componentName, componentSubdirectory, diff --git a/mpas_analysis/shared/html/pages.py b/mpas_analysis/shared/html/pages.py index 7c3640228..97edc12d5 100644 --- a/mpas_analysis/shared/html/pages.py +++ b/mpas_analysis/shared/html/pages.py @@ -8,7 +8,7 @@ from lxml import etree from collections import OrderedDict -from ..io.utility import build_config_full_path +from mpas_analysis.shared.io.utility import build_config_full_path def generate_html(config, analyses, refConfig=None): # {{{ diff --git a/mpas_analysis/shared/interpolation/__init__.py b/mpas_analysis/shared/interpolation/__init__.py index 1de243cde..adae7c0b9 100644 --- a/mpas_analysis/shared/interpolation/__init__.py +++ b/mpas_analysis/shared/interpolation/__init__.py @@ -1 +1 @@ -from .remapper import Remapper +from mpas_analysis.shared.interpolation.remapper import Remapper diff --git a/mpas_analysis/shared/interpolation/remapper.py b/mpas_analysis/shared/interpolation/remapper.py index cd15ad393..50b455a77 100644 --- a/mpas_analysis/shared/interpolation/remapper.py +++ b/mpas_analysis/shared/interpolation/remapper.py @@ -25,8 +25,8 @@ import xarray as xr import sys -from ..grid import MpasMeshDescriptor, LatLonGridDescriptor, \ - ProjectionGridDescriptor +from mpas_analysis.shared.grid import MpasMeshDescriptor, \ + LatLonGridDescriptor, ProjectionGridDescriptor class Remapper(object): diff --git a/mpas_analysis/shared/io/__init__.py b/mpas_analysis/shared/io/__init__.py index daa194070..d369a423e 100644 --- a/mpas_analysis/shared/io/__init__.py +++ b/mpas_analysis/shared/io/__init__.py @@ -1,4 +1,6 @@ -from .namelist_streams_interface import NameList, StreamsFile -from .utility import paths -from .write_netcdf import write_netcdf -from .mpas_reader import open_mpas_dataset, subset_variables +from mpas_analysis.shared.io.namelist_streams_interface import NameList, \ + StreamsFile +from mpas_analysis.shared.io.utility import paths +from mpas_analysis.shared.io.write_netcdf import write_netcdf +from mpas_analysis.shared.io.mpas_reader import open_mpas_dataset, \ + subset_variables diff --git a/mpas_analysis/shared/io/mpas_reader.py b/mpas_analysis/shared/io/mpas_reader.py index 720d9f2fd..783bb6099 100644 --- a/mpas_analysis/shared/io/mpas_reader.py +++ b/mpas_analysis/shared/io/mpas_reader.py @@ -13,7 +13,8 @@ import six import xarray -from ..timekeeping.utility import string_to_days_since_date, days_to_datetime +from mpas_analysis.shared.timekeeping.utility import \ + string_to_days_since_date, days_to_datetime def open_mpas_dataset(fileName, calendar, diff --git a/mpas_analysis/shared/io/namelist_streams_interface.py b/mpas_analysis/shared/io/namelist_streams_interface.py index c09f2f98c..f0156e114 100644 --- a/mpas_analysis/shared/io/namelist_streams_interface.py +++ b/mpas_analysis/shared/io/namelist_streams_interface.py @@ -16,9 +16,9 @@ import re import os.path -from ..containers import ReadOnlyDict -from .utility import paths -from ..timekeeping.utility import string_to_datetime +from mpas_analysis.shared.containers import ReadOnlyDict +from mpas_analysis.shared.io.utility import paths +from mpas_analysis.shared.timekeeping.utility import string_to_datetime def convert_namelist_to_dict(fname, readonly=True): diff --git a/mpas_analysis/shared/mpas_xarray/mpas_xarray.py b/mpas_analysis/shared/mpas_xarray/mpas_xarray.py index c704ee1ac..6b63ce905 100644 --- a/mpas_analysis/shared/mpas_xarray/mpas_xarray.py +++ b/mpas_analysis/shared/mpas_xarray/mpas_xarray.py @@ -7,8 +7,9 @@ import xarray from functools import partial -from ..timekeeping.utility import string_to_days_since_date, \ - string_to_datetime, days_to_datetime, datetime_to_days +from mpas_analysis.shared.timekeeping.utility import \ + string_to_days_since_date, string_to_datetime, days_to_datetime, \ + datetime_to_days """ Utility functions for importing MPAS files into xarray. diff --git a/mpas_analysis/shared/plot/plotting.py b/mpas_analysis/shared/plot/plotting.py index bebeb6346..d60a2cbb0 100644 --- a/mpas_analysis/shared/plot/plotting.py +++ b/mpas_analysis/shared/plot/plotting.py @@ -23,9 +23,10 @@ from functools import partial from mpl_toolkits.axes_grid1 import make_axes_locatable -from ..timekeeping.utility import days_to_datetime, date_to_days +from mpas_analysis.shared.timekeeping.utility import days_to_datetime, \ + date_to_days -from ..constants import constants +from mpas_analysis.shared.constants import constants from six.moves import configparser diff --git a/mpas_analysis/shared/time_series/__init__.py b/mpas_analysis/shared/time_series/__init__.py index 787036001..627ff0408 100644 --- a/mpas_analysis/shared/time_series/__init__.py +++ b/mpas_analysis/shared/time_series/__init__.py @@ -1,5 +1,7 @@ -from .time_series import cache_time_series -from .mpas_time_series_task import MpasTimeSeriesTask +from mpas_analysis.shared.time_series.time_series import cache_time_series +from mpas_analysis.shared.time_series.mpas_time_series_task import \ + MpasTimeSeriesTask -from .anomaly import compute_moving_avg_anomaly_from_start -from .moving_average import compute_moving_avg +from mpas_analysis.shared.time_series.anomaly import \ + compute_moving_avg_anomaly_from_start +from mpas_analysis.shared.time_series.moving_average import compute_moving_avg diff --git a/mpas_analysis/shared/time_series/anomaly.py b/mpas_analysis/shared/time_series/anomaly.py index 46a2d4ae8..0dfac5419 100644 --- a/mpas_analysis/shared/time_series/anomaly.py +++ b/mpas_analysis/shared/time_series/anomaly.py @@ -3,8 +3,8 @@ from __future__ import absolute_import, division, print_function, \ unicode_literals -from ..io import open_mpas_dataset -from .moving_average import compute_moving_avg +from mpas_analysis.shared.io import open_mpas_dataset +from mpas_analysis.shared.time_series.moving_average import compute_moving_avg def compute_moving_avg_anomaly_from_start(timeSeriesFileName, variableList, diff --git a/mpas_analysis/shared/time_series/mpas_time_series_task.py b/mpas_analysis/shared/time_series/mpas_time_series_task.py index 53c108daf..75755bcf8 100644 --- a/mpas_analysis/shared/time_series/mpas_time_series_task.py +++ b/mpas_analysis/shared/time_series/mpas_time_series_task.py @@ -8,10 +8,11 @@ import xarray as xr import numpy -from ..analysis_task import AnalysisTask +from mpas_analysis.shared.analysis_task import AnalysisTask -from ..io.utility import build_config_full_path, make_directories -from ..timekeeping.utility import get_simulation_start_time +from mpas_analysis.shared.io.utility import \ + build_config_full_path, make_directories +from mpas_analysis.shared.timekeeping.utility import get_simulation_start_time class MpasTimeSeriesTask(AnalysisTask): # {{{ diff --git a/mpas_analysis/shared/time_series/time_series.py b/mpas_analysis/shared/time_series/time_series.py index 76df1ab20..4dc1d6b85 100644 --- a/mpas_analysis/shared/time_series/time_series.py +++ b/mpas_analysis/shared/time_series/time_series.py @@ -13,7 +13,7 @@ import numpy import os -from ..timekeeping.utility import days_to_datetime +from mpas_analysis.shared.timekeeping.utility import days_to_datetime def cache_time_series(timesInDataSet, timeSeriesCalcFunction, cacheFileName, diff --git a/mpas_analysis/shared/timekeeping/utility.py b/mpas_analysis/shared/timekeeping/utility.py index 84a598cbc..7ddb49503 100644 --- a/mpas_analysis/shared/timekeeping/utility.py +++ b/mpas_analysis/shared/timekeeping/utility.py @@ -14,7 +14,8 @@ import numpy import six -from .MpasRelativeDelta import MpasRelativeDelta +from mpas_analysis.shared.timekeeping.MpasRelativeDelta import \ + MpasRelativeDelta def get_simulation_start_time(streams): diff --git a/mpas_analysis/test/test_mpas_config_parser.py b/mpas_analysis/test/test_mpas_config_parser.py index 38944f287..fca487ff5 100644 --- a/mpas_analysis/test/test_mpas_config_parser.py +++ b/mpas_analysis/test/test_mpas_config_parser.py @@ -13,7 +13,7 @@ from six.moves import configparser from mpas_analysis.test import TestCase, loaddatadir from mpas_analysis.configuration import MpasAnalysisConfigParser -from . import requires_numpy +from mpas_analysis.test import requires_numpy @pytest.mark.usefixtures("loaddatadir") From 3929ac011ceae1efda2996bd300a3599bf71084b Mon Sep 17 00:00:00 2001 From: Xylar Asay-Davis Date: Thu, 1 Feb 2018 18:08:01 -0700 Subject: [PATCH 05/71] Parse file-name templates from streams The filename_template attribute can now be parsed into a format that datetime.strptime can use to extract the year, month, etc. from a file name. --- mpas_analysis/ocean/streamfunction_moc.py | 12 ++++--- .../shared/io/namelist_streams_interface.py | 34 +++++++++++++++++++ 2 files changed, 42 insertions(+), 4 deletions(-) diff --git a/mpas_analysis/ocean/streamfunction_moc.py b/mpas_analysis/ocean/streamfunction_moc.py index 04c9d8a3a..2727909c0 100644 --- a/mpas_analysis/ocean/streamfunction_moc.py +++ b/mpas_analysis/ocean/streamfunction_moc.py @@ -9,7 +9,7 @@ import os from mpas_analysis.shared.constants.constants import m3ps_to_Sv -from mpas_analysis.shared.plot.plotting import plot_vertical_section,\ +from mpas_analysis.shared.plot.plotting import plot_vertical_section, \ timeseries_analysis_plot, setup_colormap from mpas_analysis.shared.io.utility import build_config_full_path, \ @@ -485,9 +485,13 @@ def _compute_moc_time_series_postprocess(self): # {{{ streamName, startDate=self.startDateTseries, endDate=self.endDateTseries, calendar=self.calendar)) - dates = sorted([fileName[-13:-6] for fileName in inputFilesTseries]) - years = np.array([int(date[0:4]) for date in dates]) - months = np.array([int(date[5:7]) for date in dates]) + template = self.historyStreams.read_datetime_template(streamName) + template = os.path.basename(template) + dts = [datetime.strptime(os.path.basename(fileName), template) for + fileName in inputFilesTseries] + + years = [dt.year for dt in dts] + months = [dt.month for dt in dts] mocRegion = np.zeros(len(inputFilesTseries)) times = np.zeros(len(inputFilesTseries)) diff --git a/mpas_analysis/shared/io/namelist_streams_interface.py b/mpas_analysis/shared/io/namelist_streams_interface.py index f0156e114..8ccf41c0c 100644 --- a/mpas_analysis/shared/io/namelist_streams_interface.py +++ b/mpas_analysis/shared/io/namelist_streams_interface.py @@ -329,6 +329,40 @@ def read(self, streamname, attribname): return stream.get(attribname) return None + def read_datetime_template(self, streamname): + """ + Get the value of the given attribute in the given stream + + Parameters + ---------- + streamname : str + The name of the stream + + Returns + ------- + value : str + The template for file names from this stream in a format accepted + by ``datetime.strptime``. This is useful for parsing the date + from a given file name. + + Authors + ------- + Xylar Asay-Davis + """ + template = self.read(streamname, 'filename_template') + replacements = {'$Y': '%Y', + '$M': '%m', + '$D': '%d', + '$S': '00000', # datetime doesn't handle seconds alone + '$h': '%H', + '$m': '%M', + '$s': '%S'} + + for old in replacements: + template = template.replace(old, replacements[old]) + + return template + def readpath(self, streamName, startDate=None, endDate=None, calendar=None): """ From 57c66aa58001b9bbc93e5f79e9191540aee52d92 Mon Sep 17 00:00:00 2001 From: Xylar Asay-Davis Date: Thu, 1 Feb 2018 18:10:17 -0700 Subject: [PATCH 06/71] Use template to parse dates from monthly mean files Instead of relying on monthly mean files having the E3SM file format, parse the year and month using the filename_template attribute from the stream. --- mpas_analysis/ocean/streamfunction_moc.py | 12 ++---- .../climatology/mpas_climatology_task.py | 9 +++-- mpas_analysis/shared/io/utility.py | 40 ++++++++++++++++++- .../time_series/mpas_time_series_task.py | 25 +++++++----- 4 files changed, 63 insertions(+), 23 deletions(-) diff --git a/mpas_analysis/ocean/streamfunction_moc.py b/mpas_analysis/ocean/streamfunction_moc.py index 2727909c0..ef310ad3b 100644 --- a/mpas_analysis/ocean/streamfunction_moc.py +++ b/mpas_analysis/ocean/streamfunction_moc.py @@ -13,7 +13,7 @@ timeseries_analysis_plot, setup_colormap from mpas_analysis.shared.io.utility import build_config_full_path, \ - make_directories + make_directories, get_files_year_month from mpas_analysis.shared.io import open_mpas_dataset @@ -485,13 +485,9 @@ def _compute_moc_time_series_postprocess(self): # {{{ streamName, startDate=self.startDateTseries, endDate=self.endDateTseries, calendar=self.calendar)) - template = self.historyStreams.read_datetime_template(streamName) - template = os.path.basename(template) - dts = [datetime.strptime(os.path.basename(fileName), template) for - fileName in inputFilesTseries] - - years = [dt.year for dt in dts] - months = [dt.month for dt in dts] + years, months = get_files_year_month(inputFilesTseries, + self.historyStreams, + 'timeSeriesStatsMonthlyOutput') mocRegion = np.zeros(len(inputFilesTseries)) times = np.zeros(len(inputFilesTseries)) diff --git a/mpas_analysis/shared/climatology/mpas_climatology_task.py b/mpas_analysis/shared/climatology/mpas_climatology_task.py index 231bf3203..6c08faaa6 100644 --- a/mpas_analysis/shared/climatology/mpas_climatology_task.py +++ b/mpas_analysis/shared/climatology/mpas_climatology_task.py @@ -13,6 +13,8 @@ get_unmasked_mpas_climatology_directory, \ get_unmasked_mpas_climatology_file_name +from ..io.utility import get_files_year_month + class MpasClimatologyTask(AnalysisTask): # {{{ ''' @@ -262,9 +264,10 @@ def _update_climatology_bounds_from_file_names(self): # {{{ requestedStartYear = config.getint('climatology', 'startYear') requestedEndYear = config.getint('climatology', 'endYear') - dates = sorted([fileName[-13:-6] for fileName in self.inputFiles]) - years = [int(date[0:4]) for date in dates] - months = [int(date[5:7]) for date in dates] + fileNames = sorted(self.inputFiles) + years, months = get_files_year_month(fileNames, + self.historyStreams, + 'timeSeriesStatsMonthlyOutput') # search for the start of the first full year firstIndex = 0 diff --git a/mpas_analysis/shared/io/utility.py b/mpas_analysis/shared/io/utility.py index 1be5d61ca..0a8923216 100644 --- a/mpas_analysis/shared/io/utility.py +++ b/mpas_analysis/shared/io/utility.py @@ -11,6 +11,7 @@ import os import random import string +from datetime import datetime def paths(*args): # {{{ @@ -95,7 +96,7 @@ def make_directories(path): # {{{ def build_config_full_path(config, section, relativePathOption, relativePathSection=None, - defaultPath=None): # {{{ + defaultPath=None): # {{{ """ Returns a full path from a base directory and a relative path @@ -134,7 +135,7 @@ def build_config_full_path(config, section, relativePathOption, if defaultPath is not None and not os.path.exists(fullPath): fullPath = defaultPath - return fullPath # }}} + return fullPath # }}} def check_path_exists(path): # {{{ @@ -159,4 +160,39 @@ def check_path_exists(path): # {{{ raise OSError('Path {} not found'.format(path)) # }}} +def get_files_year_month(fileNames, streamsFile, streamName): # {{{ + """ + Extract the year and month from file names associated with a stream + + Parameters + ---------- + fileNames : list of str + The names of files with a year and month in their names. + + streamsFile : ``StreamsFile`` + The parsed streams file, used to get a template for the + + streamName : str + The name of the stream with a file-name template for ``fileNames`` + + Returns + ------- + years, months : list of int + The years and months for each file in ``fileNames`` + + Authors + ------- + Xylar Asay-Davis + """ + + template = streamsFile.read_datetime_template(streamName) + template = os.path.basename(template) + dts = [datetime.strptime(os.path.basename(fileName), template) for + fileName in fileNames] + + years = [dt.year for dt in dts] + months = [dt.month for dt in dts] + + return years, months # }}} + # vim: foldmethod=marker ai ts=4 sts=4 et sw=4 ft=python diff --git a/mpas_analysis/shared/time_series/mpas_time_series_task.py b/mpas_analysis/shared/time_series/mpas_time_series_task.py index 75755bcf8..2c194415a 100644 --- a/mpas_analysis/shared/time_series/mpas_time_series_task.py +++ b/mpas_analysis/shared/time_series/mpas_time_series_task.py @@ -10,8 +10,8 @@ from mpas_analysis.shared.analysis_task import AnalysisTask -from mpas_analysis.shared.io.utility import \ - build_config_full_path, make_directories +from mpas_analysis.shared.io.utility import build_config_full_path, \ + make_directories, get_files_year_month from mpas_analysis.shared.timekeeping.utility import get_simulation_start_time @@ -211,9 +211,10 @@ def _update_time_series_bounds_from_file_names(self): # {{{ requestedStartYear = config.getint(section, 'startYear') requestedEndYear = config.getint(section, 'endYear') - dates = sorted([fileName[-13:-6] for fileName in self.inputFiles]) - years = [int(date[0:4]) for date in dates] - months = [int(date[5:7]) for date in dates] + fileNames = sorted(self.inputFiles) + years, months = get_files_year_month(fileNames, + self.historyStreams, + 'timeSeriesStatsMonthlyOutput') # search for the start of the first full year firstIndex = 0 @@ -289,10 +290,14 @@ def _compute_time_series_with_ncrcat(self): if updateSubset: # add only input files wiht times that aren't already in # the output file - dates = sorted([fileName[-13:-6] for fileName in - self.inputFiles]) - inYears = numpy.array([int(date[0:4]) for date in dates]) - inMonths = numpy.array([int(date[5:7]) for date in dates]) + + fileNames = sorted(self.inputFiles) + inYears, inMonths = get_files_year_month( + fileNames, self.historyStreams, + 'timeSeriesStatsMonthlyOutput') + + inYears = numpy.array(inYears) + inMonths = numpy.array(inMonths) totalMonths = 12*inYears + inMonths dates = [bytes.decode(name) for name in @@ -304,7 +309,7 @@ def _compute_time_series_with_ncrcat(self): lastTotalMonths = 12*lastYear + lastMonth inputFiles = [] - for index, inputFile in enumerate(self.inputFiles): + for index, inputFile in enumerate(fileNames): if totalMonths[index] > lastTotalMonths: inputFiles.append(inputFile) From b1064cd64c42261d9b96d394724aaaa94e92a3db Mon Sep 17 00:00:00 2001 From: Xylar Asay-Davis Date: Thu, 1 Feb 2018 20:48:00 -0700 Subject: [PATCH 07/71] Create symlinks to timeSeriesStatsMonthly output This allows us to use ncclimo even when a standalone MPAS run has used different file-naming conventions than ncclimo supports. --- .../climatology/mpas_climatology_task.py | 39 ++++++++++++++++--- 1 file changed, 34 insertions(+), 5 deletions(-) diff --git a/mpas_analysis/shared/climatology/mpas_climatology_task.py b/mpas_analysis/shared/climatology/mpas_climatology_task.py index 6c08faaa6..e4d4d2e73 100644 --- a/mpas_analysis/shared/climatology/mpas_climatology_task.py +++ b/mpas_analysis/shared/climatology/mpas_climatology_task.py @@ -13,7 +13,8 @@ get_unmasked_mpas_climatology_directory, \ get_unmasked_mpas_climatology_file_name -from ..io.utility import get_files_year_month +from ..io.utility import build_config_full_path, make_directories, \ + get_files_year_month class MpasClimatologyTask(AnalysisTask): # {{{ @@ -170,7 +171,8 @@ def setup_and_check(self): # {{{ raise IOError('No files were found in stream {} between {} and ' '{}.'.format(streamName, startDate, endDate)) - self._update_climatology_bounds_from_file_names() + self.symlinkDirectory = \ + self._update_climatology_bounds_and_create_symlinks() # }}} @@ -219,7 +221,7 @@ def run_task(self): # {{{ if not allExist: self._compute_climatologies_with_ncclimo( - inDirectory=self.historyDirectory, + inDirectory=self.symlinkDirectory, outDirectory=climatologyDirectory) # }}} @@ -249,10 +251,18 @@ def get_file_name(self, season): # {{{ # }}} - def _update_climatology_bounds_from_file_names(self): # {{{ + def _update_climatology_bounds_and_create_symlinks(self): # {{{ """ Update the start and end years and dates for climatologies based on the - years actually available in the list of files. + years actually available in the list of files. Create symlinks to + monthly mean files so they have the expected file naming convention + for ncclimo. + + Returns + ------- + symlinkDirectory : str + The path to the symlinks created for each timeSeriesStatsMonthly + input file Authors ------- @@ -306,6 +316,25 @@ def _update_climatology_bounds_from_file_names(self): # {{{ self.startYear = startYear self.endYear = endYear + # now, create the symlinks + climatologyBaseDirectory = build_config_full_path( + config, 'output', 'mpasClimatologySubdirectory') + + symlinkDirectory = '{}/source_symlinks'.format( + climatologyBaseDirectory) + + make_directories(symlinkDirectory) + + for inFileName, year, month in zip(fileNames, years, months): + outFileName = '{}/{}.hist.am.timeSeriesStatsMonthly.{:04d}-' \ + '{:02d}-01.nc'.format(symlinkDirectory, self.ncclimoModel, + year, month) + + if not os.path.exists(outFileName): + os.symlink(inFileName, outFileName) + + return symlinkDirectory + # }}} def _compute_climatologies_with_ncclimo(self, inDirectory, outDirectory, From 7034195b2dbdad9b8515c478320a86543675d058 Mon Sep 17 00:00:00 2001 From: Xylar Asay-Davis Date: Fri, 2 Feb 2018 16:28:15 -0700 Subject: [PATCH 08/71] Document setup for standalone MPAS Standalone MPAS runs need to be set up with the proper analysis members enabled and streams defined. These are now described in the documentation. Authors are now included at the end of the documentation. --- docs/authors.rst | 19 ++++++ docs/e3sm.rst | 20 ++++++ docs/index.rst | 20 +++++- docs/mpascice.rst | 63 +++++++++++++++++++ docs/mpaso.rst | 156 ++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 277 insertions(+), 1 deletion(-) create mode 100644 docs/authors.rst create mode 100644 docs/e3sm.rst create mode 100644 docs/mpascice.rst create mode 100644 docs/mpaso.rst diff --git a/docs/authors.rst b/docs/authors.rst new file mode 100644 index 000000000..3b67178e5 --- /dev/null +++ b/docs/authors.rst @@ -0,0 +1,19 @@ +Main Authors +============ +* Xylar Asay-Davis +* Milena Veniziani +* Philip Wolfram + +Contributors +============ +* Luke Van Roekel +* Greg Streletz +* Mark Petersen +* Stephen Price +* Joseph Kennedy +* Adrian Turner +* Matthew Hoffman +* Jeremy Fyke + +For a list of all the contributions: +https://github.com/MPAS-Dev/MPAS-Analysis/graphs/contributors \ No newline at end of file diff --git a/docs/e3sm.rst b/docs/e3sm.rst new file mode 100644 index 000000000..435c79f7e --- /dev/null +++ b/docs/e3sm.rst @@ -0,0 +1,20 @@ +E3SM +==== + +The Energy Exascale Earth System Model (E3SM) project, previously known as +ACME, is central to ESM as well as many of the Climate and Environmental +Sciences Division activities, as it is developing a computationally advanced +coupled climate-energy model to investigate the challenges posed by the +interactions of weather-climate scale variability with energy and related +sectors. + +A Full description of E3SM is available at: +https://climatemodeling.science.energy.gov/projects/energy-exascale-earth-system-model + +Setting up E3SM runs +-------------------- + +All online analysis and output stream within MPAS components (MPAS-O and +MPAS-SeaIce) are configured to support MPAS-Analysis without any modifications +to namelists or streams files. + diff --git a/docs/index.rst b/docs/index.rst index 1bdbce629..0431d85e6 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -23,7 +23,25 @@ Documentation api design_docs +MPAS Components and E3SM +======================== + +.. toctree:: + :maxdepth: 2 + + mpaso + mpascice + e3sm + + Indices and tables ================== -* :ref:`genindex` \ No newline at end of file +* :ref:`genindex` + +Authors +======= +.. toctree:: + :maxdepth: 1 + + authors diff --git a/docs/mpascice.rst b/docs/mpascice.rst new file mode 100644 index 000000000..ce1a3c46f --- /dev/null +++ b/docs/mpascice.rst @@ -0,0 +1,63 @@ +MPAS Sea Ice +============ + +The Model for Prediction Across Scales Sea Ice (MPAS Sea Ice, sometimes called +MPAS-CICE because of the physics it has inherited from the CICE sea-ice model) +is designed for the simulations of sea ice on unstructured grids supported by +the MPAS framework. The model has not yet been publicly released and does not +have public documentation. + +Setting up Standalone MPAS Sea Ice Runs +--------------------------------------- + +In order to support all sea=ice analysis tasks from MPAS-Analysis, certain +"analysis members", Fortran modules that perform analysis during the +simulation, need to be enabled. + +The following is a list of suggested values for namelist options, typically +found in ``namelist.cice`` or ``mpas-cice_in``:: + + config_AM_timeSeriesStatsMonthly_enable = .true. + +Additionally, the duration of the run should be set to at least two years and +typically longer before most analysis is useful:: + + config_run_duration = '0002-00-00_00:00:00' + +Several streams must be defined in the streams file, typically +``streams.cice``, (even if they will not be written out -- +``output_interval=="none"``):: + + + + + + + + + + + + +The ``filename_tempalate`` can be modified as desired (these are the defalult +values from E3SM). For the ``timeSeriesStatsMonthlyOutput`` stream, both the +filename_interval and the output_interval must currently be monthly +(``"0000-01-00_00:00:00"``). + +Additional fields can be included in the ``timeSeriesStatsMonthlyOutput`` +streams. These are the minimum that allow the analysis to run successfully. diff --git a/docs/mpaso.rst b/docs/mpaso.rst new file mode 100644 index 000000000..f84e21d33 --- /dev/null +++ b/docs/mpaso.rst @@ -0,0 +1,156 @@ +MPAS Ocean +========== + +The Model for Prediction Across Scales Ocean (MPAS-O) is designed for the +simulation of the ocean system from time scales of months to millenia and +spatial scales from sub 1 km to global circulations. + +MPAS-O has demonstrated the ability to accurately reproduce mesoscale ocean +activity with a local mesh refinement strategy. + +In addition to faciliating the study of multiscale phenomena within the ocean +system, MPAS-O is intended for the study of anthropogenic climate change as +the ocean component of climate system models. + + +Full documentaiton is available at: +https://mpas-dev.github.io/ocean/ocean.html + +Setting up Standalone MPAS-O Runs +--------------------------------- + +In order to support all ocean analysis tasks from MPAS-Analysis, certain +"analysis members", Fortran modules that perform analysis during the +simulation, need to be enabled. + +The following is a list of suggested values for namelist options, typically +found in ``namelist.ocean`` or ``mpas-o_in``:: + + config_AM_surfaceAreaWeightedAverages_enable = .true. + config_AM_surfaceAreaWeightedAverages_compute_interval = '0000-00-00_01:00:00' + config_AM_layerVolumeWeightedAverage_enable = .true. + config_AM_layerVolumeWeightedAverage_compute_interval = '0000-00-00_01:00:00' + config_AM_meridionalHeatTransport_enable = .true. + config_AM_meridionalHeatTransport_compute_interval = '0000-00-00_01:00:00' + config_AM_mixedLayerDepths_enable = .true. + config_AM_timeSeriesStatsMonthly_enable = .true. + +Additionally, the duration of the run should be set to at least two years and +typically longer before most analysis is useful:: + + config_run_duration = '0002-00-00_00:00:00' + +Several streams must be defined in the streams file, typically +``streams.ocean``, (even if they will not be written out -- +``output_intervale=="none"``):: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +The ``filename_tempalate`` can be modified as desired (in most cases, these are +the defalult values from E3SM). For the ``timeSeriesStatsMonthlyOutput`` +stream, both the filename_interval and the output_interval must currently be +monthly (``"0000-01-00_00:00:00"``). + +Additional fields can be included in the ``timeSeriesStatsMonthlyOutput`` +streams. These are the minimum that allow the analysis to run successfully. From e0dc22c8555e4255e75a4240480afaacff482353 Mon Sep 17 00:00:00 2001 From: Xylar Asay-Davis Date: Sat, 3 Feb 2018 11:56:04 -0700 Subject: [PATCH 09/71] Update CI test based on recent changes --- mpas_analysis/test/test_mpas_climatology_task.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mpas_analysis/test/test_mpas_climatology_task.py b/mpas_analysis/test/test_mpas_climatology_task.py index e336043cb..61e836856 100644 --- a/mpas_analysis/test/test_mpas_climatology_task.py +++ b/mpas_analysis/test/test_mpas_climatology_task.py @@ -112,7 +112,7 @@ def test_run_analysis(self): fileName = mpasClimatologyTask.get_file_name(season=season) assert(os.path.exists(fileName)) - def test_update_climatology_bounds_from_file_names(self): + def test_update_climatology_bounds_and_create_symlinks(self): mpasClimatologyTask = self.setup_task() config = mpasClimatologyTask.config @@ -123,7 +123,7 @@ def test_update_climatology_bounds_from_file_names(self): startDate = '{:04d}-01-01_00:00:00'.format(startYear) endDate = '{:04d}-12-31_23:59:59'.format(endYear) - mpasClimatologyTask._update_climatology_bounds_from_file_names() + mpasClimatologyTask._update_climatology_bounds_and_create_symlinks() assert(mpasClimatologyTask.startYear == startYear) assert(mpasClimatologyTask.endYear == endYear) @@ -142,7 +142,7 @@ def test_update_climatology_bounds_from_file_names(self): config.set('climatology', 'startDate', startDate) config.set('climatology', 'endDate', endDate) - mpasClimatologyTask._update_climatology_bounds_from_file_names() + mpasClimatologyTask._update_climatology_bounds_and_create_symlinks() startYear = 2 endYear = 2 From 73dc51d8fa6cc7bdacc1e8852a761f1d406a28ed Mon Sep 17 00:00:00 2001 From: Xylar Asay-Davis Date: Sun, 26 Nov 2017 18:01:22 +0100 Subject: [PATCH 10/71] Add a task for plotting the sea surface height vs. obs Uses the AVISO time series on the 1 degree grid. --- mpas_analysis/config.default | 27 +++ mpas_analysis/ocean/__init__.py | 1 + mpas_analysis/ocean/climatology_map_ssh.py | 209 +++++++++++++++++++++ run_mpas_analysis | 3 + 4 files changed, 240 insertions(+) create mode 100644 mpas_analysis/ocean/climatology_map_ssh.py diff --git a/mpas_analysis/config.default b/mpas_analysis/config.default index a96053572..292e78ddc 100644 --- a/mpas_analysis/config.default +++ b/mpas_analysis/config.default @@ -212,6 +212,7 @@ ninoSubdirectory = Nino mhtSubdirectory = MHT meltSubdirectory = Melt soseSubdirectory = SOSE +sshSubdirectory = SSH # first and last year of SST observational climatology (preferably one of the # two ranges given below) @@ -582,6 +583,32 @@ seasons = ['JFM', 'JAS', 'ANN'] # comparison grid(s) ('latlon', 'antarctic') on which to plot analysis comparisonGrids = ['latlon'] +[climatologyMapSSH] +## options related to plotting horizontally remapped climatologies of +## sea surface height (SSH) against reference model results and observations + +# colormap for model/observations +colormapNameResult = Spectral_r +# color indices into colormapName for filled contours +colormapIndicesResult = [0, 20, 40, 80, 100, 120, 160, 180, 200, 240, 255] +# colormap levels/values for contour boundaries +colorbarLevelsResult = [-2.4, -2, -1.6, -1.2, -0.8, -0.4, 0, 0.4, 0.8, 1.2] + +# colormap for differences +colormapNameDifference = RdBu_r +# color indices into colormapName for filled contours +colormapIndicesDifference = [0, 23, 46, 70, 93, 116, 128, 128, 139, 162, 185, 209, 232, 255] +# colormap levels/values for contour boundaries +colorbarLevelsDifference = [-1., -0.8, -0.6, -0.4, -0.2, -0.1, 0., 0.1, 0.2, 0.4, 0.6, 0.8, 1.] + +# Times for comparison times (Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, +# Nov, Dec, JFM, AMJ, JAS, OND, ANN) +seasons = ['JFM', 'JAS', 'ANN'] + +# comparison grid(s) ('latlon', 'antarctic') on which to plot analysis +comparisonGrids = ['latlon'] + + [climatologyMapAntarcticMelt] ## options related to plotting horizontally regridded maps of Antarctic ## sub-ice-shelf melt rates against reference model results and observations diff --git a/mpas_analysis/ocean/__init__.py b/mpas_analysis/ocean/__init__.py index 2a8097a67..359795fb5 100644 --- a/mpas_analysis/ocean/__init__.py +++ b/mpas_analysis/ocean/__init__.py @@ -1,6 +1,7 @@ from mpas_analysis.ocean.climatology_map_sst import ClimatologyMapSST from mpas_analysis.ocean.climatology_map_mld import ClimatologyMapMLD from mpas_analysis.ocean.climatology_map_sss import ClimatologyMapSSS +from mpas_analysis.ocean.climatology_map_ssh import ClimatologyMapSSH from mpas_analysis.ocean.climatology_map_antarctic_melt import \ ClimatologyMapAntarcticMelt from mpas_analysis.ocean.climatology_map_sose import \ diff --git a/mpas_analysis/ocean/climatology_map_ssh.py b/mpas_analysis/ocean/climatology_map_ssh.py new file mode 100644 index 000000000..54be7bea2 --- /dev/null +++ b/mpas_analysis/ocean/climatology_map_ssh.py @@ -0,0 +1,209 @@ +from __future__ import absolute_import, division, print_function, \ + unicode_literals + +import xarray as xr + +from mpas_analysis.shared import AnalysisTask + +from mpas_analysis.shared.io.utility import build_config_full_path + +from mpas_analysis.shared.climatology import RemapMpasClimatologySubtask, \ + RemapObservedClimatologySubtask + +from mpas_analysis.ocean.plot_climatology_map_subtask import \ + PlotClimatologyMapSubtask + +from mpas_analysis.shared.grid import LatLonGridDescriptor + + +class ClimatologyMapSSH(AnalysisTask): # {{{ + """ + An analysis task for comparison of sea surface height (ssh) against + observations + + Authors + ------- + Xylar Asay-Davis + """ + def __init__(self, config, mpasClimatologyTask, + refConfig=None): # {{{ + """ + Construct the analysis task. + + Parameters + ---------- + config : ``MpasAnalysisConfigParser`` + Configuration options + + mpasClimatologyTask : ``MpasClimatologyTask`` + The task that produced the climatology to be remapped and plotted + + refConfig : ``MpasAnalysisConfigParser``, optional + Configuration options for a reference run (if any) + + Authors + ------- + Xylar Asay-Davis + """ + fieldName = 'ssh' + # call the constructor from the base class (AnalysisTask) + super(ClimatologyMapSSH, self).__init__( + config=config, taskName='climatologyMapSSH', + componentName='ocean', + tags=['climatology', 'horizontalMap', fieldName]) + + mpasFieldName = 'timeMonthly_avg_ssh' + iselValues = None + + sectionName = self.taskName + + # read in what seasons we want to plot + seasons = config.getExpression(sectionName, 'seasons') + + if len(seasons) == 0: + raise ValueError('config section {} does not contain valid list ' + 'of seasons'.format(sectionName)) + + comparisonGridNames = config.getExpression(sectionName, + 'comparisonGrids') + + if len(comparisonGridNames) == 0: + raise ValueError('config section {} does not contain valid list ' + 'of comparison grids'.format(sectionName)) + + # the variable mpasFieldName will be added to mpasClimatologyTask + # along with the seasons. + remapClimatologySubtask = RemapMpasClimatologySubtask( + mpasClimatologyTask=mpasClimatologyTask, + parentTask=self, + climatologyName=fieldName, + variableList=[mpasFieldName], + comparisonGridNames=comparisonGridNames, + seasons=seasons, + iselValues=iselValues) + + if refConfig is None: + + refTitleLabel = 'Observations (AVISO sea-level anomaly)' + + observationsDirectory = build_config_full_path( + config, 'oceanObservations', + '{}Subdirectory'.format(fieldName)) + + obsFileName = \ + "{}/zos_AVISO_L4_199210-201012.nc".format( + observationsDirectory) + refFieldName = 'zos' + outFileLabel = 'sshAVISO' + galleryName = 'Observations: AVISO' + + remapObservationsSubtask = RemapObservedSSHClimatology( + parentTask=self, seasons=seasons, fileName=obsFileName, + outFilePrefix=refFieldName, + comparisonGridNames=comparisonGridNames) + self.add_subtask(remapObservationsSubtask) + diffTitleLabel = 'Model - Observations' + + else: + remapObservationsSubtask = None + refRunName = refConfig.get('runs', 'mainRunName') + galleryName = None + refTitleLabel = 'Ref: {}'.format(refRunName) + + refFieldName = mpasFieldName + outFileLabel = 'ssh' + diffTitleLabel = 'Main - Reference' + + for comparisonGridName in comparisonGridNames: + for season in seasons: + # make a new subtask for this season and comparison grid + subtask = PlotClimatologyMapSubtask(self, season, + comparisonGridName, + remapClimatologySubtask, + remapObservationsSubtask, + refConfig) + + subtask.set_plot_info( + outFileLabel=outFileLabel, + fieldNameInTitle='SSH', + mpasFieldName=mpasFieldName, + refFieldName=refFieldName, + refTitleLabel=refTitleLabel, + diffTitleLabel=diffTitleLabel, + unitsLabel=r'm', + imageCaption='Mean Sea Surface Height', + galleryGroup='Sea Surface Height', + groupSubtitle=None, + groupLink='ssh', + galleryName=galleryName) + + self.add_subtask(subtask) + # }}} + # }}} + + +class RemapObservedSSHClimatology(RemapObservedClimatologySubtask): # {{{ + """ + A subtask for reading and remapping SSH observations + + Authors + ------- + Xylar Asay-Davis + """ + + def get_observation_descriptor(self, fileName): # {{{ + ''' + get a MeshDescriptor for the observation grid + + Parameters + ---------- + fileName : str + observation file name describing the source grid + + Returns + ------- + obsDescriptor : ``MeshDescriptor`` + The descriptor for the observation grid + + Authors + ------- + Xylar Asay-Davis + ''' + + # create a descriptor of the observation grid using the lat/lon + # coordinates + obsDescriptor = LatLonGridDescriptor.read(fileName=fileName, + latVarName='lat', + lonVarName='lon') + return obsDescriptor # }}} + + def build_observational_dataset(self, fileName): # {{{ + ''' + read in the data sets for observations, and possibly rename some + variables and dimensions + + Parameters + ---------- + fileName : str + observation file name + + Returns + ------- + dsObs : ``xarray.Dataset`` + The observational dataset + + Authors + ------- + Xylar Asay-Davis + ''' + + dsObs = xr.open_dataset(fileName) + dsObs.rename({'time': 'Time'}, inplace=True) + dsObs.coords['month'] = dsObs['Time.month'] + dsObs.coords['year'] = dsObs['Time.year'] + + return dsObs # }}} + + # }}} + +# vim: foldmethod=marker ai ts=4 sts=4 et sw=4 ft=python diff --git a/run_mpas_analysis b/run_mpas_analysis index 53d1de451..9c4aa4e1b 100755 --- a/run_mpas_analysis +++ b/run_mpas_analysis @@ -85,6 +85,8 @@ def build_analysis_list(config, refConfig): # {{{ refConfig)) analyses.append(ocean.ClimatologyMapSSS(config, oceanClimatolgyTask, refConfig)) + analyses.append(ocean.ClimatologyMapSSH(config, oceanClimatolgyTask, + refConfig)) analyses.append(ocean.ClimatologyMapSoseTemperature( config, oceanClimatolgyTask, refConfig)) analyses.append(ocean.ClimatologyMapSoseSalinity( @@ -107,6 +109,7 @@ def build_analysis_list(config, refConfig): # {{{ refConfig)) analyses.append(ocean.MeridionalHeatTransport(config, oceanClimatolgyTask, refConfig)) + analyses.append(ocean.StreamfunctionMOC(config, oceanClimatolgyTask)) analyses.append(ocean.IndexNino34(config, oceanIndexTask, refConfig)) From b89f6ebc4c9c98333707f83a6bbe4211c642916e Mon Sep 17 00:00:00 2001 From: Xylar Asay-Davis Date: Wed, 21 Feb 2018 20:59:44 -0700 Subject: [PATCH 11/71] Change diff color map to be white near zero This was not the case for SST, SSS and MLD, which could lead to meaningless blue/pink speckle. --- mpas_analysis/config.default | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/mpas_analysis/config.default b/mpas_analysis/config.default index a96053572..9d0573eea 100644 --- a/mpas_analysis/config.default +++ b/mpas_analysis/config.default @@ -521,9 +521,9 @@ colorbarLevelsResult = [-2, 0, 2, 6, 10, 16, 22, 26, 28, 32] # colormap for differences colormapNameDifference = RdBu_r # color indices into colormapName for filled contours -colormapIndicesDifference = [0, 28, 57, 85, 113, 142, 170, 198, 227, 255] +colormapIndicesDifference = [0, 28, 57, 85, 113, 128, 128, 142, 170, 198, 227, 255] # colormap levels/values for contour boundaries -colorbarLevelsDifference = [-5, -3, -2, -1, 0, 1, 2, 3, 5] +colorbarLevelsDifference = [-5, -3, -2, -1, -0.1, 0, 0.1, 1, 2, 3, 5] # Times for comparison times (Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, # Nov, Dec, JFM, AMJ, JAS, OND, ANN) @@ -546,9 +546,9 @@ colorbarLevelsResult = [28, 29, 30, 31, 32, 33, 34, 35, 36, 38] # colormap for differences colormapNameDifference = RdBu_r # color indices into colormapName for filled contours -colormapIndicesDifference = [0, 28, 57, 85, 113, 142, 170, 198, 227, 255] +colormapIndicesDifference = [0, 28, 57, 85, 113, 128, 128, 142, 170, 198, 227, 255] # colormap levels/values for contour boundaries -colorbarLevelsDifference = [-3, -2, -1, -0.5, 0, 0.5, 1, 2, 3] +colorbarLevelsDifference = [-3, -2, -1, -0.5, -0.02, 0, 0.02, 0.5, 1, 2, 3] # Times for comparison times (Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, # Nov, Dec, JFM, AMJ, JAS, OND, ANN) @@ -571,9 +571,9 @@ colorbarLevelsResult = [0, 20, 40, 60, 80, 100, 150, 200, 400, 800] # colormap for differences colormapNameDifference = RdBu_r # color indices into colormapName for filled contours -colormapIndicesDifference = [0, 28, 57, 85, 113, 142, 170, 198, 227, 255] +colormapIndicesDifference = [0, 28, 57, 85, 113, 128, 128, 142, 170, 198, 227, 255] # colormap levels/values for contour boundaries -colorbarLevelsDifference = [-150, -80, -30, -10, 0, 10, 30, 80, 150] +colorbarLevelsDifference = [-150, -80, -30, -10, -1, 0, 1, 10, 30, 80, 150] # Times for comparison times (Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, # Nov, Dec, JFM, AMJ, JAS, OND, ANN) @@ -711,9 +711,9 @@ colorbarLevelsResult = [0.15, 0.3, 0.5, 0.7, 0.8, 0.85, 0.9, 0.95, 1] # colormap for differences colormapNameDifference = RdBu_r # color indices into colormapName for filled contours -colormapIndicesDifference = [0, 32, 64, 96, 128, 128, 160, 192, 224, 255] +colormapIndicesDifference = [0, 32, 64, 96, 112, 128, 128, 144, 160, 192, 224, 255] # colormap levels/values for contour boundaries -colorbarLevelsDifference = [-1., -0.8, -0.6, -0.4, -0.2, 0, 0.2, 0.4, 0.6, 0.8, 1.] +colorbarLevelsDifference = [-1., -0.8, -0.6, -0.4, -0.2, -0.1, 0, 0.1, 0.2, 0.4, 0.6, 0.8, 1.] # Times for comparison times (These should be left unchanged, since # observations are only available for these seasons) @@ -747,9 +747,9 @@ colorbarLevelsResult = [0.15, 0.3, 0.5, 0.7, 0.8, 0.85, 0.9, 0.95, 1] # colormap for differences colormapNameDifference = RdBu_r # color indices into colormapName for filled contours -colormapIndicesDifference = [0, 32, 64, 96, 128, 128, 160, 192, 224, 255] +colormapIndicesDifference = [0, 32, 64, 96, 112, 128, 128, 144, 160, 192, 224, 255] # colormap levels/values for contour boundaries -colorbarLevelsDifference = [-1., -0.8, -0.6, -0.4, -0.2, 0, 0.2, 0.4, 0.6, 0.8, 1.] +colorbarLevelsDifference = [-1., -0.8, -0.6, -0.4, -0.2, -0.1, 0, 0.1, 0.2, 0.4, 0.6, 0.8, 1.] # Times for comparison times (These should be left unchanged, since # observations are only available for these seasons) From 3cf765c076a9d932e4cb03a6b9a85ee20348920b Mon Sep 17 00:00:00 2001 From: Xylar Asay-Davis Date: Wed, 21 Feb 2018 23:09:21 -0700 Subject: [PATCH 12/71] Optionally add bolus velocity to MOC By default, the bolus velocity is added as long as GM is turned on. --- mpas_analysis/config.default | 5 +++ mpas_analysis/ocean/streamfunction_moc.py | 43 ++++++++++++++++++++--- 2 files changed, 43 insertions(+), 5 deletions(-) diff --git a/mpas_analysis/config.default b/mpas_analysis/config.default index a96053572..bdae25598 100644 --- a/mpas_analysis/config.default +++ b/mpas_analysis/config.default @@ -442,6 +442,11 @@ movingAveragePoints = 1 ## options related to plotting the streamfunction of the meridional overturning ## circulation (MOC) +# Include the bolus velocity from the Gent-McWilliams parameterization? This +# only needs to be disabled if the simulation was run with GM turned on but +# the MOC shouldn't include the bolus term +includeBolus = True + # Region names for basin MOC calculation. # Supported options are Atlantic and IndoPacific regionNames = ['Atlantic'] diff --git a/mpas_analysis/ocean/streamfunction_moc.py b/mpas_analysis/ocean/streamfunction_moc.py index 04c9d8a3a..1af9c9cbc 100644 --- a/mpas_analysis/ocean/streamfunction_moc.py +++ b/mpas_analysis/ocean/streamfunction_moc.py @@ -112,8 +112,17 @@ def setup_and_check(self): # {{{ self.sectionName = 'streamfunctionMOC' + self.includeBolus = config.getboolean(self.sectionName, 'includeBolus') + if self.includeBolus: + # only add the bolus velocity if GM is enabled + self.includeBolus = self.namelist.getbool('config_use_standardgm') + self.variableList = ['timeMonthly_avg_normalVelocity', 'timeMonthly_avg_vertVelocityTop'] + if self.includeBolus: + self.variableList.extend( + ['timeMonthly_avg_normalGMBolusVelocity', + 'timeMonthly_avg_vertGMBolusVelocityTop']) self.mpasClimatologyTask.add_variables(variableList=self.variableList, seasons=['ANN']) @@ -351,11 +360,21 @@ def _compute_moc_climo_postprocess(self): # {{{ climatologyFileName = self.mpasClimatologyTask.get_file_name( season='ANN') annualClimatology = xr.open_dataset(climatologyFileName) - # rename some variables for convenience - annualClimatology = annualClimatology.rename( + annualClimatology = annualClimatology.isel(Time=0) + + if self.includeBolus: + annualClimatology['avgNormalVelocity'] = \ + annualClimatology['timeMonthly_avg_normalVelocity'] + \ + annualClimatology['timeMonthly_avg_normalGMBolusVelocity'] + + annualClimatology['avgVertVelocityTop'] = \ + annualClimatology['timeMonthly_avg_vertVelocityTop'] + \ + annualClimatology['timeMonthly_avg_vertGMBolusVelocityTop'] + else: + # rename some variables for convenience + annualClimatology = annualClimatology.rename( {'timeMonthly_avg_normalVelocity': 'avgNormalVelocity', 'timeMonthly_avg_vertVelocityTop': 'avgVertVelocityTop'}) - annualClimatology = annualClimatology.isel(Time=0) # Convert to numpy arrays # (can result in a memory error for large array size) @@ -534,8 +553,22 @@ def _compute_moc_time_series_postprocess(self): # {{{ self.logger.info(' date: {:04d}-{:02d}'.format(date.year, date.month)) - horizontalVel = dsLocal.timeMonthly_avg_normalVelocity.values - verticalVel = dsLocal.timeMonthly_avg_vertVelocityTop.values + if self.includeBolus: + dsLocal['avgNormalVelocity'] = \ + dsLocal['timeMonthly_avg_normalVelocity'] + \ + dsLocal['timeMonthly_avg_normalGMBolusVelocity'] + + dsLocal['avgVertVelocityTop'] = \ + dsLocal['timeMonthly_avg_vertVelocityTop'] + \ + dsLocal['timeMonthly_avg_vertGMBolusVelocityTop'] + else: + # rename some variables for convenience + dsLocal = dsLocal.rename( + {'timeMonthly_avg_normalVelocity': 'avgNormalVelocity', + 'timeMonthly_avg_vertVelocityTop': 'avgVertVelocityTop'}) + + horizontalVel = dsLocal.avgNormalVelocity.values + verticalVel = dsLocal.avgVertVelocityTop.values velArea = verticalVel * areaCell[:, np.newaxis] transportZ = self._compute_transport(maxEdgesInTransect, transectEdgeGlobalIDs, From 93ef78e4bc3a3bcd0a074c04f19fb91bf91303cf Mon Sep 17 00:00:00 2001 From: Luke Van Roekel Date: Thu, 22 Feb 2018 13:51:17 -0600 Subject: [PATCH 13/71] Fixes path to MOC mask on anvil --- .../anvil/config.20170926.FCT2.A_WCYCL1850S.ne30_oECv3.anvil | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configs/anvil/config.20170926.FCT2.A_WCYCL1850S.ne30_oECv3.anvil b/configs/anvil/config.20170926.FCT2.A_WCYCL1850S.ne30_oECv3.anvil index 2768885a2..c96b7444a 100644 --- a/configs/anvil/config.20170926.FCT2.A_WCYCL1850S.ne30_oECv3.anvil +++ b/configs/anvil/config.20170926.FCT2.A_WCYCL1850S.ne30_oECv3.anvil @@ -142,4 +142,4 @@ polarPlot = False ## options related to ocean regions used in several analysis modules # Directory for region mask files -regionMaskDirectory = /global/project/projectdirs/acme/mapping/grids/ +regionMaskDirectory = /lcrc/group/acme/mpas_analysis/region_masks From c477e2983ba5d6d6fed290cfe44e9b9b54c11f20 Mon Sep 17 00:00:00 2001 From: Xylar Asay-Davis Date: Thu, 22 Feb 2018 16:10:44 -0700 Subject: [PATCH 14/71] Switch from m to cm --- mpas_analysis/config.default | 4 +- mpas_analysis/ocean/climatology_map_ssh.py | 47 ++++++++++++++++++++- mpas_analysis/shared/constants/constants.py | 3 ++ 3 files changed, 50 insertions(+), 4 deletions(-) diff --git a/mpas_analysis/config.default b/mpas_analysis/config.default index 292e78ddc..2eb7f729c 100644 --- a/mpas_analysis/config.default +++ b/mpas_analysis/config.default @@ -592,14 +592,14 @@ colormapNameResult = Spectral_r # color indices into colormapName for filled contours colormapIndicesResult = [0, 20, 40, 80, 100, 120, 160, 180, 200, 240, 255] # colormap levels/values for contour boundaries -colorbarLevelsResult = [-2.4, -2, -1.6, -1.2, -0.8, -0.4, 0, 0.4, 0.8, 1.2] +colorbarLevelsResult = [-240., -200., -160., -120., -80., -40., 0., 40., 80., 120.] # colormap for differences colormapNameDifference = RdBu_r # color indices into colormapName for filled contours colormapIndicesDifference = [0, 23, 46, 70, 93, 116, 128, 128, 139, 162, 185, 209, 232, 255] # colormap levels/values for contour boundaries -colorbarLevelsDifference = [-1., -0.8, -0.6, -0.4, -0.2, -0.1, 0., 0.1, 0.2, 0.4, 0.6, 0.8, 1.] +colorbarLevelsDifference = [-100., -80., -60., -40., -20., -10., 0., 10., 20., 40., 60., 80., 100.] # Times for comparison times (Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, # Nov, Dec, JFM, AMJ, JAS, OND, ANN) diff --git a/mpas_analysis/ocean/climatology_map_ssh.py b/mpas_analysis/ocean/climatology_map_ssh.py index 54be7bea2..fe59d3b4d 100644 --- a/mpas_analysis/ocean/climatology_map_ssh.py +++ b/mpas_analysis/ocean/climatology_map_ssh.py @@ -15,6 +15,8 @@ from mpas_analysis.shared.grid import LatLonGridDescriptor +from mpas_analysis.shared.constants import constants + class ClimatologyMapSSH(AnalysisTask): # {{{ """ @@ -73,7 +75,7 @@ def __init__(self, config, mpasClimatologyTask, # the variable mpasFieldName will be added to mpasClimatologyTask # along with the seasons. - remapClimatologySubtask = RemapMpasClimatologySubtask( + remapClimatologySubtask = RemapSSHClimatology( mpasClimatologyTask=mpasClimatologyTask, parentTask=self, climatologyName=fieldName, @@ -130,7 +132,7 @@ def __init__(self, config, mpasClimatologyTask, refFieldName=refFieldName, refTitleLabel=refTitleLabel, diffTitleLabel=diffTitleLabel, - unitsLabel=r'm', + unitsLabel=r'cm', imageCaption='Mean Sea Surface Height', galleryGroup='Sea Surface Height', groupSubtitle=None, @@ -142,6 +144,44 @@ def __init__(self, config, mpasClimatologyTask, # }}} +class RemapSSHClimatology(RemapMpasClimatologySubtask): # {{{ + """ + Change units from m to cm + + Authors + ------- + Xylar Asay-Davis + """ + + def customize_masked_climatology(self, climatology): # {{{ + """ + Mask the melt rates using ``landIceMask`` and rescale it to m/yr + + Parameters + ---------- + climatology : ``xarray.Dataset`` object + the climatology data set + + Returns + ------- + climatology : ``xarray.Dataset`` object + the modified climatology data set + + Authors + ------- + Xylar Asay-Davis + """ + + fieldName = self.variableList[0] + + # scale the field to cm from m + climatology[fieldName] = constants.cm_per_m * climatology[fieldName] + + return climatology # }}} + + # }}} + + class RemapObservedSSHClimatology(RemapObservedClimatologySubtask): # {{{ """ A subtask for reading and remapping SSH observations @@ -202,6 +242,9 @@ def build_observational_dataset(self, fileName): # {{{ dsObs.coords['month'] = dsObs['Time.month'] dsObs.coords['year'] = dsObs['Time.year'] + # scale the field to cm from m + dsObs['zos'] = constants.cm_per_m * dsObs['zos'] + return dsObs # }}} # }}} diff --git a/mpas_analysis/shared/constants/constants.py b/mpas_analysis/shared/constants/constants.py index 9f901aadf..7231fe7be 100644 --- a/mpas_analysis/shared/constants/constants.py +++ b/mpas_analysis/shared/constants/constants.py @@ -64,4 +64,7 @@ # kilograms per gigatonne kg_per_GT = 1e12 +# cm per m +cm_per_m = 100. + # vim: foldmethod=marker ai ts=4 sts=4 et sw=4 ft=python From d1fcf7df5d940cd58028b51feedf1da4a8de45d1 Mon Sep 17 00:00:00 2001 From: Xylar Asay-Davis Date: Thu, 22 Feb 2018 12:54:20 -0800 Subject: [PATCH 15/71] Use common colormap setup for all plots with colormaps All support either contours (via indexed colormaps) or continuous plotting (via a norm). Tick marks can be specified (optionally) differently from contour levels. --- .../mpas_analysis_config_parser.py | 4 +- .../ocean/meridional_heat_transport.py | 25 +- .../ocean/plot_climatology_map_subtask.py | 22 +- mpas_analysis/ocean/plot_hovmoller_subtask.py | 20 +- mpas_analysis/ocean/streamfunction_moc.py | 18 +- .../sea_ice/plot_climatology_map_subtask.py | 13 +- mpas_analysis/shared/plot/plotting.py | 553 ++++++++++-------- 7 files changed, 340 insertions(+), 315 deletions(-) diff --git a/mpas_analysis/configuration/mpas_analysis_config_parser.py b/mpas_analysis/configuration/mpas_analysis_config_parser.py index 3bf3cf643..06f2472cf 100644 --- a/mpas_analysis/configuration/mpas_analysis_config_parser.py +++ b/mpas_analysis/configuration/mpas_analysis_config_parser.py @@ -22,8 +22,8 @@ if six.PY3: xrange = range -npallow = dict(linspace=np.linspace, xrange=xrange, range=range, - arange=np.arange, pi=np.pi, Pi=np.pi, __builtins__=None) +npallow = dict(linspace=np.linspace, xrange=xrange, range=range, array=np.array, + arange=np.arange, pi=np.pi, Pi=np.pi, int=int, __builtins__=None) class MpasAnalysisConfigParser(ConfigParser): diff --git a/mpas_analysis/ocean/meridional_heat_transport.py b/mpas_analysis/ocean/meridional_heat_transport.py index f1dbfd0fc..218203f41 100644 --- a/mpas_analysis/ocean/meridional_heat_transport.py +++ b/mpas_analysis/ocean/meridional_heat_transport.py @@ -6,8 +6,7 @@ import numpy as np import os -from mpas_analysis.shared.plot.plotting import plot_vertical_section,\ - setup_colormap, plot_1D +from mpas_analysis.shared.plot.plotting import plot_vertical_section, plot_1D from mpas_analysis.shared.io.utility import build_config_full_path, \ make_directories @@ -16,9 +15,6 @@ from mpas_analysis.shared import AnalysisTask from mpas_analysis.shared.html import write_image_xml -from mpas_analysis.shared.climatology import \ - get_unmasked_mpas_climatology_file_name - class MeridionalHeatTransport(AnalysisTask): # {{{ ''' @@ -174,7 +170,6 @@ def run_task(self): # {{{ '{}/meridionalHeatTransport_years{:04d}-{:04d}.nc'.format( outputDirectory, self.startYear, self.endYear) - if os.path.exists(outFileName): self.logger.info(' Reading results from previous analysis run...') annualClimatology = xr.open_dataset(outFileName) @@ -342,18 +337,12 @@ def run_task(self): # {{{ filePrefix = self.filePrefixes['mhtZ'] figureName = '{}/{}.png'.format(self.plotsDirectory, filePrefix) colorbarLabel = '[PW/m]' - contourLevels = config.getExpression(self.sectionName, - 'contourLevelsGlobal', - usenumpyfunc=True) - (colormapName, colorbarLevels) = setup_colormap(config, - self.sectionName, - suffix='Global') - plot_vertical_section(config, x, y, z, - colormapName, colorbarLevels, - contourLevels, colorbarLabel, - title, xLabel, yLabel, figureName, - xLim=xLimGlobal, yLim=depthLimGlobal, - invertYAxis=False, N=movingAveragePoints) + plot_vertical_section(config, x, y, z, self.sectionName, + suffix='', colorbarLabel=colorbarLabel, + title=title, xlabel=xLabel, ylabel=yLabel, + fileout=figureName, xLim=xLimGlobal, + yLim=depthLimGlobal, invertYAxis=False, + N=movingAveragePoints) self._write_xml(filePrefix) diff --git a/mpas_analysis/ocean/plot_climatology_map_subtask.py b/mpas_analysis/ocean/plot_climatology_map_subtask.py index 34b11d39d..66395a887 100644 --- a/mpas_analysis/ocean/plot_climatology_map_subtask.py +++ b/mpas_analysis/ocean/plot_climatology_map_subtask.py @@ -16,7 +16,7 @@ from mpas_analysis.shared import AnalysisTask from mpas_analysis.shared.plot.plotting import plot_global_comparison, \ - setup_colormap, plot_polar_projection_comparison + plot_polar_projection_comparison from mpas_analysis.shared.html import write_image_xml @@ -386,11 +386,6 @@ def _plot_latlon(self, remappedModelClimatology, remappedRefClimatology): mainRunName = config.get('runs', 'mainRunName') - (colormapResult, colorbarLevelsResult) = setup_colormap( - config, configSectionName, suffix='Result') - (colormapDifference, colorbarLevelsDifference) = setup_colormap( - config, configSectionName, suffix='Difference') - modelOutput = nans_to_numpy_mask( remappedModelClimatology[self.mpasFieldName].values) @@ -419,10 +414,7 @@ def _plot_latlon(self, remappedModelClimatology, remappedRefClimatology): modelOutput, refOutput, bias, - colormapResult, - colorbarLevelsResult, - colormapDifference, - colorbarLevelsDifference, + configSectionName, fileout=outFileName, title=title, modelTitle='{}'.format(mainRunName), @@ -483,15 +475,6 @@ def _plot_antarctic(self, remappedModelClimatology, self.fieldNameInTitle, season, self.startYear, self.endYear) - if config.has_option(configSectionName, 'colormapIndicesResult'): - colorMapType = 'indexed' - elif config.has_option(configSectionName, 'normTypeResult'): - colorMapType = 'norm' - else: - raise ValueError('config section {} contains neither the info' - 'for an indexed color map nor for computing a ' - 'norm'.format(configSectionName)) - plot_polar_projection_comparison( config, x, @@ -502,7 +485,6 @@ def _plot_antarctic(self, remappedModelClimatology, bias, fileout=outFileName, colorMapSectionName=configSectionName, - colorMapType=colorMapType, title=title, modelTitle='{}'.format(mainRunName), refTitle=self.refTitleLabel, diff --git a/mpas_analysis/ocean/plot_hovmoller_subtask.py b/mpas_analysis/ocean/plot_hovmoller_subtask.py index 96e54a284..8543325e8 100644 --- a/mpas_analysis/ocean/plot_hovmoller_subtask.py +++ b/mpas_analysis/ocean/plot_hovmoller_subtask.py @@ -8,8 +8,7 @@ from mpas_analysis.shared import AnalysisTask -from mpas_analysis.shared.plot.plotting import plot_vertical_section, \ - setup_colormap +from mpas_analysis.shared.plot.plotting import plot_vertical_section from mpas_analysis.shared.io import open_mpas_dataset @@ -260,18 +259,11 @@ def run_task(self): # {{{ figureName = '{}/{}.png'.format(self.plotsDirectory, self.filePrefix) - (colormapName, colorbarLevels) = setup_colormap(config, - self.sectionName) - - contourLevels = config.getExpression(self.sectionName, - 'contourLevels', - usenumpyfunc=True) - - plot_vertical_section(config, Time, depth, field, - colormapName, colorbarLevels, contourLevels, - self.unitsLabel, title, xLabel, yLabel, - figureName, linewidths=1, xArrayIsTime=True, - calendar=self.calendar) + plot_vertical_section(config, Time, depth, field, self.sectionName, + suffix='', colorbarLabel=self.unitsLabel, + title=title, xlabel=xLabel, ylabel=yLabel, + fileout=figureName, linewidths=1, + xArrayIsTime=True, calendar=self.calendar) write_image_xml( config=config, diff --git a/mpas_analysis/ocean/streamfunction_moc.py b/mpas_analysis/ocean/streamfunction_moc.py index ef310ad3b..5b7ec216c 100644 --- a/mpas_analysis/ocean/streamfunction_moc.py +++ b/mpas_analysis/ocean/streamfunction_moc.py @@ -9,8 +9,8 @@ import os from mpas_analysis.shared.constants.constants import m3ps_to_Sv -from mpas_analysis.shared.plot.plotting import plot_vertical_section, \ - timeseries_analysis_plot, setup_colormap +from mpas_analysis.shared.plot.plotting import plot_vertical_section,\ + timeseries_analysis_plot from mpas_analysis.shared.io.utility import build_config_full_path, \ make_directories, get_files_year_month @@ -197,20 +197,14 @@ def run_task(self): # {{{ mainRunName) filePrefix = self.filePrefixes[region] figureName = '{}/{}.png'.format(self.plotsDirectory, filePrefix) - contourLevels = \ - config.getExpression(self.sectionName, - 'contourLevels{}'.format(region), - usenumpyfunc=True) - (colormapName, colorbarLevels) = setup_colormap(config, - self.sectionName, - suffix=region) x = self.lat[region] y = self.depth z = self.moc[region] - plot_vertical_section(config, x, y, z, colormapName, - colorbarLevels, contourLevels, colorbarLabel, - title, xLabel, yLabel, figureName, + plot_vertical_section(config, x, y, z, self.sectionName, + suffix=region, colorbarLabel=colorbarLabel, + title=title, xlabel=xLabel, ylabel=yLabel, + fileout=figureName, N=movingAveragePointsClimatological) caption = '{} Meridional Overturning Streamfunction'.format(region) diff --git a/mpas_analysis/sea_ice/plot_climatology_map_subtask.py b/mpas_analysis/sea_ice/plot_climatology_map_subtask.py index 5ca70ff2e..5393ee826 100644 --- a/mpas_analysis/sea_ice/plot_climatology_map_subtask.py +++ b/mpas_analysis/sea_ice/plot_climatology_map_subtask.py @@ -9,8 +9,7 @@ from mpas_analysis.shared import AnalysisTask -from mpas_analysis.shared.plot.plotting import plot_polar_comparison, \ - setup_colormap +from mpas_analysis.shared.plot.plotting import plot_polar_comparison from mpas_analysis.shared.html import write_image_xml @@ -298,11 +297,6 @@ def run_task(self): # {{{ else: plotProjection = 'spstere' - (colormapResult, colorbarLevelsResult) = setup_colormap( - config, sectionName, suffix='Result') - (colormapDifference, colorbarLevelsDifference) = setup_colormap( - config, sectionName, suffix='Difference') - referenceLongitude = config.getfloat(sectionName, 'referenceLongitude') minimumLatitude = config.getfloat(sectionName, @@ -373,10 +367,7 @@ def run_task(self): # {{{ modelOutput, refOutput, difference, - colormapResult, - colorbarLevelsResult, - colormapDifference, - colorbarLevelsDifference, + sectionName, title=title, fileout=fileout, plotProjection=plotProjection, diff --git a/mpas_analysis/shared/plot/plotting.py b/mpas_analysis/shared/plot/plotting.py index d60a2cbb0..54d768322 100644 --- a/mpas_analysis/shared/plot/plotting.py +++ b/mpas_analysis/shared/plot/plotting.py @@ -13,6 +13,7 @@ from __future__ import absolute_import, division, print_function, \ unicode_literals +import matplotlib import matplotlib.pyplot as plt import matplotlib.colors as cols import xarray as xr @@ -261,7 +262,7 @@ def timeseries_analysis_plot_polar(config, dsvalues, N, title, majorTickLocs[month] = majorTickLocs[month-1] + \ ((constants.daysInMonth[month-1] * np.pi * 2.0) / 365.0) minorTickLocs[month] = minorTickLocs[month-1] + \ - (((constants.daysInMonth[month-1] + \ + (((constants.daysInMonth[month-1] + constants.daysInMonth[month]) * np.pi) / 365.0) ax.set_xticks(majorTickLocs) @@ -273,7 +274,6 @@ def timeseries_analysis_plot_polar(config, dsvalues, N, title, if titleFontSize is None: titleFontSize = config.get('plot', 'titleFontSize') - axis_font = {'size': config.get('plot', 'axisFontSize')} title_font = {'size': titleFontSize, 'color': config.get('plot', 'titleFontColor'), 'weight': config.get('plot', 'titleFontWeight')} @@ -294,10 +294,7 @@ def plot_polar_comparison( modelArray, refArray, diffArray, - cmapModelRef, - clevsModelRef, - cmapDiff, - clevsDiff, + colorMapSectionName, fileout, title=None, plotProjection='npstere', @@ -330,17 +327,8 @@ def plot_polar_comparison( diffArray : float array difference between modelArray and refArray - cmapModelRef : str - colormap of model and observations or reference run panel - - clevsModelRef : int array - colorbar values for model and observations or reference run panel - - cmapDiff : str - colormap of difference (bias) panel - - clevsDiff : int array - colorbar values for difference (bias) panel + colorMapSectionName : str + section name in ``config`` where color map info can be found. fileout : str the file name to be written @@ -383,7 +371,8 @@ def plot_polar_comparison( Xylar Asay-Davis, Milena Veneziani """ - def do_subplot(ax, field, title, cmap, norm, levels): + def do_subplot(ax, field, title, colormap, norm, levels, ticks, contours, + lineWidth, lineColor): """ Make a subplot within the figure. """ @@ -398,16 +387,28 @@ def do_subplot(ax, field, title, cmap, norm, levels): m.drawparallels(np.arange(-80., 81., 10.)) m.drawmeridians(np.arange(-180., 181., 20.), labels=[True, False, True, True]) - cs = m.contourf(x, y, field, cmap=cmap, norm=norm, - levels=levels) - cbar = m.colorbar(cs, location='right', pad="3%", spacing='uniform', - ticks=levels, boundaries=levels) + if levels is None: + plotHandle = m.pcolormesh(x, y, field, cmap=colormap, norm=norm) + else: + plotHandle = m.contourf(x, y, field, cmap=colormap, norm=norm, + levels=levels) + + if contours is not None: + matplotlib.rcParams['contour.negative_linestyle'] = 'solid' + m.contour(x, y, field, levels=contours, colors=lineColor, + linewidths=lineWidth) + + cbar = m.colorbar(plotHandle, location='right', pad="3%", + spacing='uniform', ticks=ticks, boundaries=levels) cbar.set_label(cbarlabel) if dpi is None: dpi = config.getint('plot', 'dpi') + dictModelRef = setup_colormap(config, colorMapSectionName, suffix='Result') + dictDiff = setup_colormap(config, colorMapSectionName, suffix='Difference') + if refArray is None: if figsize is None: figsize = (8, 8.5) @@ -432,21 +433,15 @@ def do_subplot(ax, field, title, cmap, norm, levels): fig.suptitle(title, y=0.95, **title_font) axis_font = {'size': config.get('plot', 'axisFontSize')} - normModelRef = cols.BoundaryNorm(clevsModelRef, cmapModelRef.N) - normDiff = cols.BoundaryNorm(clevsDiff, cmapDiff.N) - ax = plt.subplot(subplots[0]) - do_subplot(ax=ax, field=modelArray, title=modelTitle, cmap=cmapModelRef, - norm=normModelRef, levels=clevsModelRef) + do_subplot(ax=ax, field=modelArray, title=modelTitle, **dictModelRef) if refArray is not None: ax = plt.subplot(subplots[1]) - do_subplot(ax=ax, field=refArray, title=refTitle, cmap=cmapModelRef, - norm=normModelRef, levels=clevsModelRef) + do_subplot(ax=ax, field=refArray, title=refTitle, **dictModelRef) ax = plt.subplot(subplots[2]) - do_subplot(ax=ax, field=diffArray, title=diffTitle, cmap=cmapDiff, - norm=normDiff, levels=clevsDiff) + do_subplot(ax=ax, field=diffArray, title=diffTitle, **dictDiff) plt.tight_layout(pad=4.) if vertical: @@ -460,25 +455,24 @@ def do_subplot(ax, field, title, cmap, norm, levels): def plot_global_comparison( - config, - Lons, - Lats, - modelArray, - refArray, - diffArray, - cmapModelRef, - clevsModelRef, - cmapDiff, - clevsDiff, - fileout, - title=None, - modelTitle='Model', - refTitle='Observations', - diffTitle='Model-Observations', - cbarlabel='units', - titleFontSize=None, - figsize=(8, 13), - dpi=None): + config, + Lons, + Lats, + modelArray, + refArray, + diffArray, + colorMapSectionName, + fileout, + title=None, + modelTitle='Model', + refTitle='Observations', + diffTitle='Model-Observations', + cbarlabel='units', + titleFontSize=None, + figsize=(8, 13), + dpi=None, + lineWidth=1, + lineColor='black'): """ Plots a data set as a longitude/latitude map. @@ -498,17 +492,8 @@ def plot_global_comparison( diffArray : float array difference between modelArray and refArray - cmapModelRef : str - colormap of model and observations or reference run panel - - clevsModelRef : int array - colorbar values for model and observations or reference run panel - - cmapDiff : str - colormap of difference (bias) panel - - clevsDiff : int array - colorbar values for difference (bias) panel + colorMapSectionName : str + section name in ``config`` where color map info can be found. fileout : str the file name to be written @@ -538,11 +523,42 @@ def plot_global_comparison( the number of dots per inch of the figure, taken from section ``plot`` option ``dpi`` in the config file by default + lineWidth : int, optional + the line width of contour lines (if specified) + + lineColor : str, optional + the color contour lines (if specified) + Authors ------- Xylar Asay-Davis, Milena Veneziani """ + def plot_panel(title, array, colormap, norm, levels, ticks, contours, + lineWidth, lineColor): + plt.title(title, y=1.06, **axis_font) + m.drawcoastlines() + m.fillcontinents(color='grey', lake_color='white') + m.drawparallels(np.arange(-80., 80., 20.), + labels=[True, False, False, False]) + m.drawmeridians(np.arange(-180., 180., 60.), + labels=[False, False, False, True]) + + if levels is None: + plotHandle = m.pcolormesh(x, y, array, cmap=colormap, norm=norm) + else: + plotHandle = m.contourf(x, y, array, cmap=colormap, norm=norm, + levels=levels, extend='both') + + if contours is not None: + matplotlib.rcParams['contour.negative_linestyle'] = 'solid' + m.contour(x, y, array, levels=contours, colors=lineColor, + linewidths=lineWidth) + + cbar = m.colorbar(plotHandle, location='right', pad="5%", + spacing='uniform', ticks=ticks, boundaries=ticks) + cbar.set_label(cbarlabel) + # set up figure if dpi is None: dpi = config.getint('plot', 'dpi') @@ -560,52 +576,20 @@ def plot_global_comparison( urcrnrlon=181, resolution='l') x, y = m(Lons, Lats) # compute map proj coordinates - normModelRef = cols.BoundaryNorm(clevsModelRef, cmapModelRef.N) - normDiff = cols.BoundaryNorm(clevsDiff, cmapDiff.N) + dictModelRef = setup_colormap(config, colorMapSectionName, suffix='Result') + dictDiff = setup_colormap(config, colorMapSectionName, suffix='Difference') if refArray is not None: plt.subplot(3, 1, 1) - plt.title(modelTitle, y=1.06, **axis_font) - m.drawcoastlines() - m.fillcontinents(color='grey', lake_color='white') - m.drawparallels(np.arange(-80., 80., 20.), - labels=[True, False, False, False]) - m.drawmeridians(np.arange(-180., 180., 60.), - labels=[False, False, False, True]) - cs = m.contourf(x, y, modelArray, cmap=cmapModelRef, norm=normModelRef, - levels=clevsModelRef, extend='both') - cbar = m.colorbar(cs, location='right', pad="5%", spacing='uniform', - ticks=clevsModelRef, boundaries=clevsModelRef) - cbar.set_label(cbarlabel) + + plot_panel(modelTitle, modelArray, **dictModelRef) if refArray is not None: plt.subplot(3, 1, 2) - plt.title(refTitle, y=1.06, **axis_font) - m.drawcoastlines() - m.fillcontinents(color='grey', lake_color='white') - m.drawparallels(np.arange(-80., 80., 20.), - labels=[True, False, False, False]) - m.drawmeridians(np.arange(-180., 180., 40.), - labels=[False, False, False, True]) - cs = m.contourf(x, y, refArray, cmap=cmapModelRef, norm=normModelRef, - levels=clevsModelRef, extend='both') - cbar = m.colorbar(cs, location='right', pad="5%", spacing='uniform', - ticks=clevsModelRef, boundaries=clevsModelRef) - cbar.set_label(cbarlabel) + plot_panel(refTitle, refArray, **dictModelRef) plt.subplot(3, 1, 3) - plt.title(diffTitle, y=1.06, **axis_font) - m.drawcoastlines() - m.fillcontinents(color='grey', lake_color='white') - m.drawparallels(np.arange(-80., 80., 20.), - labels=[True, False, False, False]) - m.drawmeridians(np.arange(-180., 180., 40.), - labels=[False, False, False, True]) - cs = m.contourf(x, y, diffArray, cmap=cmapDiff, norm=normDiff, - levels=clevsDiff, extend='both') - cbar = m.colorbar(cs, location='right', pad="5%", spacing='uniform', - ticks=clevsDiff, boundaries=clevsModelRef) - cbar.set_label(cbarlabel) + plot_panel(diffTitle, diffArray, **dictDiff) if (fileout is not None): plt.savefig(fileout, dpi=dpi, bbox_inches='tight', pad_inches=0.1) @@ -624,7 +608,6 @@ def plot_polar_projection_comparison( diffArray, fileout, colorMapSectionName, - colorMapType='norm', title=None, modelTitle='Model', refTitle='Observations', @@ -662,22 +645,6 @@ def plot_polar_projection_comparison( colorMapSectionName : str section name in ``config`` where color map info can be found. - colorMapType : {'norm', 'indexed'}, optional - The type of color map, either a matplotlib norm or indices into a color - map. - - If 'norm', the following options must be defined for suffixes - ``Result`` and ``Difference``: - ``colormapName``, ``normType``, - ``normArgs``, ``colorbarTicks`` - - If 'indexed', these options are required: - ``colormapName``, ``colormapIndices``, - ``colorbarLevels`` - - The colorbar for each panel will be constructed from these options - - title : str, optional the subtitle of the plot @@ -716,21 +683,31 @@ def plot_polar_projection_comparison( Xylar Asay-Davis """ - def plot_panel(ax, title, array, cmap, norm, ticks): + def plot_panel(ax, title, array, colormap, norm, levels, ticks, contours, + lineWidth, lineColor): plt.title(title, y=1.06, **axis_font) - mesh = plt.pcolormesh(x, y, array, cmap=cmap, norm=norm) + if levels is None: + plotHandle = plt.pcolormesh(x, y, array, cmap=colormap, norm=norm) + else: + plotHandle = plt.contourf(x, y, array, cmap=colormap, norm=norm, + levels=levels, extend='both') plt.pcolormesh(x, y, landMask, cmap=landColorMap) plt.contour(xCenter, yCenter, landMask.mask, (0.5,), colors='k', linewidths=0.5) + if contours is not None: + matplotlib.rcParams['contour.negative_linestyle'] = 'solid' + plt.contour(x, y, array, levels=contours, colors=lineColor, + linewidths=lineWidth) + # create an axes on the right side of ax. The width of cax will be 5% # of ax and the padding between cax and ax will be fixed at 0.05 inch. divider = make_axes_locatable(ax) cax = divider.append_axes("right", size="5%", pad=0.05) - cbar = plt.colorbar(mesh, cax=cax) + cbar = plt.colorbar(plotHandle, cax=cax) cbar.set_label(cbarlabel) if ticks is not None: cbar.set_ticks(ticks) @@ -757,36 +734,8 @@ def plot_panel(ax, title, array, cmap, norm, ticks): figsize = (22, 7.5) subplots = [131, 132, 133] - if colorMapType == 'norm': - (cmapModelRef, normModelRef) = _setup_colormap_and_norm( - config, colorMapSectionName, suffix='Result') - (cmapDiff, normDiff) = _setup_colormap_and_norm( - config, colorMapSectionName, suffix='Difference') - - if config.has_option(colorMapSectionName, 'colorbarTicksResult'): - colorbarTicksResult = config.getExpression(colorMapSectionName, - 'colorbarTicksResult', - usenumpyfunc=True) - else: - colorbarTicksResult = None - if config.has_option(colorMapSectionName, 'colorbarTicksDifference'): - colorbarTicksDifference = config.getExpression( - colorMapSectionName, 'colorbarTicksDifference', - usenumpyfunc=True) - else: - colorbarTicksDifference = None - - elif colorMapType == 'indexed': - - (cmapModelRef, colorbarTicksResult) = setup_colormap( - config, colorMapSectionName, suffix='Result') - (cmapDiff, colorbarTicksDifference) = setup_colormap( - config, colorMapSectionName, suffix='Difference') - - normModelRef = cols.BoundaryNorm(colorbarTicksResult, cmapModelRef.N) - normDiff = cols.BoundaryNorm(colorbarTicksDifference, cmapDiff.N) - else: - raise ValueError('colorMapType must be one of {norm, indexed}') + dictModelRef = setup_colormap(config, colorMapSectionName, suffix='Result') + dictDiff = setup_colormap(config, colorMapSectionName, suffix='Difference') # set up figure fig = plt.figure(figsize=figsize, dpi=dpi) @@ -808,17 +757,14 @@ def plot_panel(ax, title, array, cmap, norm, ticks): yCenter = 0.5*(y[1:] + y[0:-1]) ax = plt.subplot(subplots[0]) - plot_panel(ax, modelTitle, modelArray, cmapModelRef, normModelRef, - colorbarTicksResult) + plot_panel(ax, modelTitle, modelArray, **dictModelRef) if refArray is not None: ax = plt.subplot(subplots[1]) - plot_panel(ax, refTitle, refArray, cmapModelRef, normModelRef, - colorbarTicksResult) + plot_panel(ax, refTitle, refArray, **dictModelRef) ax = plt.subplot(subplots[2]) - plot_panel(ax, diffTitle, diffArray, cmapDiff, normDiff, - colorbarTicksDifference) + plot_panel(ax, diffTitle, diffArray, **dictDiff) if (fileout is not None): plt.savefig(fileout, dpi=dpi, bbox_inches='tight', pad_inches=0.1) @@ -949,28 +895,27 @@ def plot_1D(config, xArrays, fieldArrays, errArrays, def plot_vertical_section( - config, - xArray, - depthArray, - fieldArray, - colormapName, - colorbarLevels, - contourLevels, - colorbarLabel=None, - title=None, - xlabel=None, - ylabel=None, - fileout='moc.png', - figsize=(10, 4), - dpi=None, - xLim=None, - yLim=None, - linewidths=2, - invertYAxis=True, - xArrayIsTime=False, - N=None, - maxXTicks=20, - calendar='gregorian'): # {{{ + config, + xArray, + depthArray, + fieldArray, + colorMapSectionName, + suffix='', + colorbarLabel=None, + title=None, + xlabel=None, + ylabel=None, + fileout='moc.png', + figsize=(10, 4), + dpi=None, + xLim=None, + yLim=None, + linewidths=2, + invertYAxis=True, + xArrayIsTime=False, + N=None, + maxXTicks=20, + calendar='gregorian'): # {{{ """ Plots a data set as a x distance (latitude, longitude, @@ -986,7 +931,8 @@ def plot_vertical_section( control plotting xArray : float array - x array (latitude, longitude, or spherical distance; or, time for a Hovmoller plot) + x array (latitude, longitude, or spherical distance; or, time for a + Hovmoller plot) depthArray : float array depth array [m] @@ -994,17 +940,11 @@ def plot_vertical_section( fieldArray : float array field array to plot - colormapName : str - colormap of plot - - colorbarLevels : int array - colorbar levels of plot - - contourLevels : int levels - levels of contours to be drawn + colorMapSectionName : str + section name in ``config`` where color map info can be found. - colorbarLabel : str, optional - label of the colorbar + suffix : str, optional + the suffix used for colorbar config options title : str, optional title of plot @@ -1040,9 +980,10 @@ def plot_vertical_section( N : int, optional the number of points over which to perform a moving average NOTE: this option is mostly intended for use when xArrayIsTime is True, - although it will work with other data as well. Also, the moving average - calculation is based on number of points, not actual x axis values, so for - best results, the values in the xArray should be equally spaced. + although it will work with other data as well. Also, the moving + average calculation is based on number of points, not actual x axis + values, so for best results, the values in the xArray should be equally + spaced. maxXTicks : int, optional the maximum number of tick marks that will be allowed along the x axis. @@ -1058,7 +999,8 @@ def plot_vertical_section( Milena Veneziani, Mark Petersen, Xylar Asay-Davis, Greg Streletz """ - # verify that the dimensions of fieldArray are consistent with those of xArray and depthArray + # verify that the dimensions of fieldArray are consistent with those of + # xArray and depthArray if len(xArray) != fieldArray.shape[1]: raise ValueError('size mismatch between xArray and fieldArray') elif len(depthArray) != fieldArray.shape[0]: @@ -1069,12 +1011,15 @@ def plot_vertical_section( dpi = config.getint('plot', 'dpi') plt.figure(figsize=figsize, dpi=dpi) - if N is not None and N != 1: # compute moving averages with respect to the x dimension + # compute moving averages with respect to the x dimension + if N is not None and N != 1: movingAverageDepthSlices = [] for nVertLevel in range(len(depthArray)): depthSlice = fieldArray[[nVertLevel]][0] - depthSlice = xr.DataArray(depthSlice) # in case it's not an xarray already - mean = pd.Series.rolling(depthSlice.to_series(), N, center=True).mean() + # in case it's not an xarray already + depthSlice = xr.DataArray(depthSlice) + mean = pd.Series.rolling(depthSlice.to_series(), N, + center=True).mean() mean = xr.DataArray.from_series(mean) mean = mean[int(N/2.0):-int(round(N/2.0)-1)] movingAverageDepthSlices.append(mean) @@ -1083,21 +1028,23 @@ def plot_vertical_section( x, y = np.meshgrid(xArray, depthArray) # change to zMid - if colorbarLevels is None: - normModelObs = None - else: - normModelObs = cols.BoundaryNorm(colorbarLevels, colormapName.N) + colormapDict = setup_colormap(config, colorMapSectionName, suffix=suffix) - cs = plt.contourf(x, y, fieldArray, cmap=colormapName, norm=normModelObs, - levels=colorbarLevels, extend='both') + cs = plt.contourf(x, y, fieldArray, cmap=colormapDict['colormap'], + norm=colormapDict['norm'], + levels=colormapDict['levels'], extend='both') + contourLevels = colormapDict['contours'] if contourLevels is not None: if len(contourLevels) == 0: - contourLevels = None # automatic calculation of contour levels - plt.contour(x, y, fieldArray, levels=contourLevels, colors='k', linewidths=linewidths) + # automatic calculation of contour levels + contourLevels = None + plt.contour(x, y, fieldArray, levels=contourLevels, colors='k', + linewidths=linewidths) cbar = plt.colorbar(cs, orientation='vertical', spacing='uniform', - ticks=colorbarLevels, boundaries=colorbarLevels) + ticks=colormapDict['ticks'], + boundaries=colormapDict['ticks']) if colorbarLabel is not None: cbar.set_label(colorbarLabel) @@ -1152,13 +1099,28 @@ def setup_colormap(config, configSectionName, suffix=''): suffix: str, optional suffix of colormap related options + colorMapType + Returns ------- - colormap : srt - new colormap + colormapDict : dict + A dictionary of colormap information. - colorbarLevels : int array - colorbar levels + 'colormap' specifies the name of the new colormap + + 'norm' is a matplotlib norm object used to normalize the colormap + + 'levels' is an array of contour levels or ``None`` if not using indexed + color map + + 'ticks' is an array of values where ticks should be placed + + 'contours' is an array of contour values to plot or ``None`` if none + have been specified + + 'lineWidth' is the width of contour lines or ``None`` if not specified + + 'lineColor' is the color of contour lines or ``None`` if not specified Authors ------- @@ -1167,38 +1129,42 @@ def setup_colormap(config, configSectionName, suffix=''): _register_custom_colormaps() - colormap = plt.get_cmap(config.get(configSectionName, - 'colormapName{}'.format(suffix))) - - indices = config.getExpression(configSectionName, - 'colormapIndices{}'.format(suffix), - usenumpyfunc=True) + if config.has_option(configSectionName, + 'colormapIndices{}'.format(suffix)): + (colormap, norm, levels, ticks) = _setup_indexed_colormap( + config, configSectionName, suffix=suffix) + elif config.has_option(configSectionName, 'normType{}'.format(suffix)): + (colormap, norm, ticks) = _setup_colormap_and_norm( + config, configSectionName, suffix=suffix) + levels = None + else: + raise ValueError('config section {} contains neither the info' + 'for an indexed color map nor for computing a ' + 'norm'.format(configSectionName)) + + option = 'contourLevels{}'.format(suffix) + if config.has_option(configSectionName, option): + contours = config.getExpression(configSectionName, + option, + usenumpyfunc=True) + else: + contours = None - try: - colorbarLevels = config.getExpression(configSectionName, - 'colorbarLevels{}'.format(suffix), - usenumpyfunc=True) - except(configparser.NoOptionError): - colorbarLevels = None + option = 'contourThickness{}'.format(suffix) + if config.has_option(configSectionName, option): + lineWidth = config.getfloat(configSectionName, option) + else: + lineWidth = None - if colorbarLevels is not None: - # set under/over values based on the first/last indices in the colormap - underColor = colormap(indices[0]) - overColor = colormap(indices[-1]) - if len(colorbarLevels)+1 == len(indices): - # we have 2 extra values for the under/over so make the colormap - # without these values - indices = indices[1:-1] - elif len(colorbarLevels)-1 != len(indices): - # indices list must be either one element shorter - # or one element longer than colorbarLevels list - raise ValueError('length mismatch between indices and colorbarLevels') - colormap = cols.ListedColormap(colormap(indices), - 'colormapName{}'.format(suffix)) - colormap.set_under(underColor) - colormap.set_over(overColor) + option = 'contourColor{}'.format(suffix) + if config.has_option(configSectionName, option): + lineColor = config.get(configSectionName, option) + else: + lineColor = None - return (colormap, colorbarLevels) + return {'colormap': colormap, 'norm': norm, 'levels': levels, + 'ticks': ticks, 'contours': contours, 'lineWidth': lineWidth, + 'lineColor': lineColor} def plot_xtick_format(plt, calendar, minDays, maxDays, maxXTicks): @@ -1273,6 +1239,9 @@ def _setup_colormap_and_norm(config, configSectionName, suffix=''): norm : ``SymLogNorm`` object the norm used to normalize the colormap + ticks : array of float + the tick marks on the colormap + Authors ------- Xylar Asay-Davis @@ -1296,7 +1265,93 @@ def _setup_colormap_and_norm(config, configSectionName, suffix=''): raise ValueError('Unsupported norm type {} in section {}'.format( normType, configSectionName)) - return (colormap, norm) + try: + ticks = config.getExpression( + configSectionName, 'colorbarTicks{}'.format(suffix), + usenumpyfunc=True) + except(configparser.NoOptionError): + ticks = None + + return (colormap, norm, ticks) + + +def _setup_indexed_colormap(config, configSectionName, suffix=''): + + ''' + Set up a colormap from the registry + + Parameters + ---------- + config : instance of ConfigParser + the configuration, containing a [plot] section with options that + control plotting + + configSectionName : str + name of config section + + suffix: str, optional + suffix of colormap related options + + colorMapType + + Returns + ------- + colormap : srt + new colormap + + norm : ``SymLogNorm`` object + the norm used to normalize the colormap + + ticks : array of float + the tick marks on the colormap + + Authors + ------- + Xylar Asay-Davis, Milena Veneziani, Greg Streletz + ''' + + colormap = plt.get_cmap(config.get(configSectionName, + 'colormapName{}'.format(suffix))) + + indices = config.getExpression(configSectionName, + 'colormapIndices{}'.format(suffix), + usenumpyfunc=True) + + try: + levels = config.getExpression( + configSectionName, 'colorbarLevels{}'.format(suffix), + usenumpyfunc=True) + except(configparser.NoOptionError): + levels = None + + if levels is not None: + # set under/over values based on the first/last indices in the colormap + underColor = colormap(indices[0]) + overColor = colormap(indices[-1]) + if len(levels)+1 == len(indices): + # we have 2 extra values for the under/over so make the colormap + # without these values + indices = indices[1:-1] + elif len(levels)-1 != len(indices): + # indices list must be either one element shorter + # or one element longer than colorbarLevels list + raise ValueError('length mismatch between indices and ' + 'colorbarLevels') + colormap = cols.ListedColormap(colormap(indices), + 'colormapName{}'.format(suffix)) + colormap.set_under(underColor) + colormap.set_over(overColor) + + norm = cols.BoundaryNorm(levels, colormap.N) + + try: + ticks = config.getExpression( + configSectionName, 'colorbarTicks{}'.format(suffix), + usenumpyfunc=True) + except(configparser.NoOptionError): + ticks = levels + + return (colormap, norm, levels, ticks) def _date_tick(days, pos, calendar='gregorian', includeMonth=True): @@ -1426,5 +1481,27 @@ def _register_custom_colormaps(): plt.register_cmap(name, colorMap) + name = 'Maximenko' + colorArray = np.array([ + [-1, 0., 0.45882352941, 0.76470588235], + [-0.666667, 0., 0.70196078431, 0.90588235294], + [-0.333333, 0.3294117647, 0.87058823529, 1.], + [0., 0.76470588235, 0.94509803921, 0.98039215686], + [0.333333, 1., 1., 0.], + [0.666667, 1., 0.29411764705, 0.], + [1, 1., 0., 0.]], float) + + colorCount = 255 + colorList = np.ones((colorCount, 4), float) + x = colorArray[:, 0] + for cIndex in range(3): + colorList[:, cIndex] = np.interp( + np.linspace(-1., 1., colorCount), + x, colorArray[:, cIndex+1]) + + colorMap = cols.LinearSegmentedColormap.from_list( + name, colorList, N=255) + + plt.register_cmap(name, colorMap) # vim: foldmethod=marker ai ts=4 sts=4 et sw=4 ft=python From 3768ba013677bda4eacb4e48e15961e342ec54d8 Mon Sep 17 00:00:00 2001 From: Xylar Asay-Davis Date: Thu, 22 Feb 2018 22:34:21 -0700 Subject: [PATCH 16/71] Change SSH to match Maximenko dynamic topography --- mpas_analysis/config.default | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/mpas_analysis/config.default b/mpas_analysis/config.default index caba17636..6ae09c339 100644 --- a/mpas_analysis/config.default +++ b/mpas_analysis/config.default @@ -588,11 +588,21 @@ comparisonGrids = ['latlon'] ## sea surface height (SSH) against reference model results and observations # colormap for model/observations -colormapNameResult = Spectral_r +#colormapNameResult = Spectral_r +colormapNameResult = Maximenko # color indices into colormapName for filled contours -colormapIndicesResult = [0, 20, 40, 80, 100, 120, 160, 180, 200, 240, 255] +colormapIndicesResult = numpy.array(numpy.linspace(0, 255, 38), int) # colormap levels/values for contour boundaries -colorbarLevelsResult = [-240., -200., -160., -120., -80., -40., 0., 40., 80., 120.] +colorbarLevelsResult = numpy.arange(-240., 130., 10.) +# colormap levels/values for ticks (defaults to same as levels) +colorbarTicksResult = numpy.arange(-240., 160., 40.) + +# contour line levels +contourLevelsResult = numpy.arange(-240., 130., 10.) +# contour line thickness +contourThicknessResult = 0.25 +# contour color +contourColorResult = 0.25 # colormap for differences colormapNameDifference = RdBu_r From cf0f1b701e4efa2b14dff0fc886cbf8040619d44 Mon Sep 17 00:00:00 2001 From: Xylar Asay-Davis Date: Fri, 23 Feb 2018 11:34:04 -0700 Subject: [PATCH 17/71] add SSH task to the docs --- docs/api.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/api.rst b/docs/api.rst index 5a240eff0..857656b6b 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -51,6 +51,7 @@ Ocean tasks ClimatologyMapSST ClimatologyMapSSS ClimatologyMapMLD + ClimatologyMapSSH ClimatologyMapAntarcticMelt IndexNino34 MeridionalHeatTransport From d1d5a8a2c02fc9622ebbc2ab8ea8b50d48dbf777 Mon Sep 17 00:00:00 2001 From: Xylar Asay-Davis Date: Fri, 23 Feb 2018 12:00:55 -0700 Subject: [PATCH 18/71] Remove mean from SSH (model and obs) Also change to pressure-adjusted SSH and change some of the title text. --- mpas_analysis/ocean/climatology_map_ssh.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/mpas_analysis/ocean/climatology_map_ssh.py b/mpas_analysis/ocean/climatology_map_ssh.py index fe59d3b4d..c5e2c24ee 100644 --- a/mpas_analysis/ocean/climatology_map_ssh.py +++ b/mpas_analysis/ocean/climatology_map_ssh.py @@ -54,7 +54,8 @@ def __init__(self, config, mpasClimatologyTask, componentName='ocean', tags=['climatology', 'horizontalMap', fieldName]) - mpasFieldName = 'timeMonthly_avg_ssh' + mpasFieldName = 'timeMonthly_avg_pressureAdjustedSSH' + iselValues = None sectionName = self.taskName @@ -86,7 +87,8 @@ def __init__(self, config, mpasClimatologyTask, if refConfig is None: - refTitleLabel = 'Observations (AVISO sea-level anomaly)' + refTitleLabel = 'Observations (AVISO Dynamic ' \ + 'Topography, 1993-2010)' observationsDirectory = build_config_full_path( config, 'oceanObservations', @@ -127,7 +129,7 @@ def __init__(self, config, mpasClimatologyTask, subtask.set_plot_info( outFileLabel=outFileLabel, - fieldNameInTitle='SSH', + fieldNameInTitle='Zero-mean SSH', mpasFieldName=mpasFieldName, refFieldName=refFieldName, refTitleLabel=refTitleLabel, @@ -176,6 +178,9 @@ def customize_masked_climatology(self, climatology): # {{{ # scale the field to cm from m climatology[fieldName] = constants.cm_per_m * climatology[fieldName] + # remove the mean + climatology[fieldName] = climatology[fieldName] - \ + climatology[fieldName].mean() return climatology # }}} @@ -245,6 +250,9 @@ def build_observational_dataset(self, fileName): # {{{ # scale the field to cm from m dsObs['zos'] = constants.cm_per_m * dsObs['zos'] + # remove the mean + dsObs['zos'] = dsObs['zos'] -dsObs['zos'].mean() + return dsObs # }}} # }}} From 62196cf827e53d63cb7584f45be92df524c7f259 Mon Sep 17 00:00:00 2001 From: Xylar Asay-Davis Date: Fri, 23 Feb 2018 11:58:09 -0800 Subject: [PATCH 19/71] Remove the mean from model and obs SSH with common mask This leads to a bias plot that just shows differences in spatial pattern, not mean offsets. --- mpas_analysis/ocean/climatology_map_ssh.py | 8 +---- .../ocean/plot_climatology_map_subtask.py | 35 ++++++++++++++++++- 2 files changed, 35 insertions(+), 8 deletions(-) diff --git a/mpas_analysis/ocean/climatology_map_ssh.py b/mpas_analysis/ocean/climatology_map_ssh.py index c5e2c24ee..bab7483f6 100644 --- a/mpas_analysis/ocean/climatology_map_ssh.py +++ b/mpas_analysis/ocean/climatology_map_ssh.py @@ -125,7 +125,7 @@ def __init__(self, config, mpasClimatologyTask, comparisonGridName, remapClimatologySubtask, remapObservationsSubtask, - refConfig) + refConfig, removeMean=True) subtask.set_plot_info( outFileLabel=outFileLabel, @@ -178,9 +178,6 @@ def customize_masked_climatology(self, climatology): # {{{ # scale the field to cm from m climatology[fieldName] = constants.cm_per_m * climatology[fieldName] - # remove the mean - climatology[fieldName] = climatology[fieldName] - \ - climatology[fieldName].mean() return climatology # }}} @@ -250,9 +247,6 @@ def build_observational_dataset(self, fileName): # {{{ # scale the field to cm from m dsObs['zos'] = constants.cm_per_m * dsObs['zos'] - # remove the mean - dsObs['zos'] = dsObs['zos'] -dsObs['zos'].mean() - return dsObs # }}} # }}} diff --git a/mpas_analysis/ocean/plot_climatology_map_subtask.py b/mpas_analysis/ocean/plot_climatology_map_subtask.py index 66395a887..3d68a766b 100644 --- a/mpas_analysis/ocean/plot_climatology_map_subtask.py +++ b/mpas_analysis/ocean/plot_climatology_map_subtask.py @@ -57,6 +57,13 @@ class PlotClimatologyMapSubtask(AnalysisTask): # {{{ The subtask for remapping the MPAS climatology for the reference run that this subtask will plot + removeMean : bool, optional + If True, a common mask for the model and reference data sets is + computed (where both are valid) and the mean over that mask is + subtracted from both the model and reference results. This is + useful for data sets where the desire is to compare the spatial + pattern but the mean offset is not meaningful (e.g. SSH) + outFileLabel : str The prefix on each plot and associated XML file @@ -106,7 +113,7 @@ class PlotClimatologyMapSubtask(AnalysisTask): # {{{ def __init__(self, parentTask, season, comparisonGridName, remapMpasClimatologySubtask, remapObsClimatologySubtask=None, - refConfig=None, depth=None): + refConfig=None, depth=None, removeMean=False): # {{{ ''' Construct one analysis subtask for each plot (i.e. each season and @@ -139,6 +146,13 @@ def __init__(self, parentTask, season, comparisonGridName, Depth the data is being plotted, 'top' for the sea surface 'bot' for the sea floor + removeMean : bool, optional + If True, a common mask for the model and reference data sets is + computed (where both are valid) and the mean over that mask is + subtracted from both the model and reference results. This is + useful for data sets where the desire is to compare the spatial + pattern but the mean offset is not meaningful (e.g. SSH) + Authors ------- Xylar Asay-Davis @@ -151,6 +165,7 @@ def __init__(self, parentTask, season, comparisonGridName, self.remapMpasClimatologySubtask = remapMpasClimatologySubtask self.remapObsClimatologySubtask = remapObsClimatologySubtask self.refConfig = refConfig + self.removeMean = removeMean subtaskName = 'plot{}_{}'.format(season, comparisonGridName) if depth is None: @@ -369,6 +384,24 @@ def run_task(self): # {{{ remappedRefClimatology = remappedRefClimatology.sel( depthSlice=str(depth), drop=True) + if self.removeMean: + if remappedRefClimatology is None: + remappedModelClimatology[self.mpasFieldName] = \ + remappedModelClimatology[self.mpasFieldName] - \ + remappedModelClimatology[self.mpasFieldName].mean() + else: + masked = remappedModelClimatology[self.mpasFieldName].where( + remappedRefClimatology[self.refFieldName].notnull()) + remappedModelClimatology[self.mpasFieldName] = \ + remappedModelClimatology[self.mpasFieldName] - \ + masked.mean() + + masked = remappedRefClimatology[self.refFieldName].where( + remappedModelClimatology[self.mpasFieldName].notnull()) + remappedRefClimatology[self.refFieldName] = \ + remappedRefClimatology[self.refFieldName] - \ + masked.mean() + if self.comparisonGridName == 'latlon': self._plot_latlon(remappedModelClimatology, remappedRefClimatology) elif self.comparisonGridName == 'antarctic': From 45146bf7053bea76c0d54f344d52b753f1bb1933 Mon Sep 17 00:00:00 2001 From: "Adrian K. Turner" Date: Mon, 26 Feb 2018 12:41:34 -0700 Subject: [PATCH 20/71] Minor modifications to MPAS-Seaice documentation --- docs/{mpascice.rst => mpasseaice.rst} | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) rename docs/{mpascice.rst => mpasseaice.rst} (93%) diff --git a/docs/mpascice.rst b/docs/mpasseaice.rst similarity index 93% rename from docs/mpascice.rst rename to docs/mpasseaice.rst index ce1a3c46f..78060d37b 100644 --- a/docs/mpascice.rst +++ b/docs/mpasseaice.rst @@ -1,8 +1,7 @@ -MPAS Sea Ice +MPAS-Seaice ============ -The Model for Prediction Across Scales Sea Ice (MPAS Sea Ice, sometimes called -MPAS-CICE because of the physics it has inherited from the CICE sea-ice model) +The Model for Prediction Across Scales Sea Ice (MPAS-Seaice) is designed for the simulations of sea ice on unstructured grids supported by the MPAS framework. The model has not yet been publicly released and does not have public documentation. From 5552d71e9c7e25433c76b53bebae101b778b218d Mon Sep 17 00:00:00 2001 From: Xylar Asay-Davis Date: Wed, 7 Mar 2018 14:31:49 -0700 Subject: [PATCH 21/71] Add ability to not use ncremap in MPAS remap task Also, switch the depth-slice remapping task to not use ncremap, since the depth coordinate seems to confuse ncremap. --- .../ocean/remap_depth_slices_subtask.py | 2 +- .../remap_mpas_climatology_subtask.py | 31 ++++++++++++++----- 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/mpas_analysis/ocean/remap_depth_slices_subtask.py b/mpas_analysis/ocean/remap_depth_slices_subtask.py index b2102ae59..7af2a7b35 100644 --- a/mpas_analysis/ocean/remap_depth_slices_subtask.py +++ b/mpas_analysis/ocean/remap_depth_slices_subtask.py @@ -86,7 +86,7 @@ def __init__(self, mpasClimatologyTask, parentTask, climatologyName, # (RemapMpasClimatologySubtask) super(RemapDepthSlicesSubtask, self).__init__( mpasClimatologyTask, parentTask, climatologyName, variableList, - seasons, comparisonGridNames, iselValues) + seasons, comparisonGridNames, iselValues, useNcremap=False) def run_task(self): # {{{ """ diff --git a/mpas_analysis/shared/climatology/remap_mpas_climatology_subtask.py b/mpas_analysis/shared/climatology/remap_mpas_climatology_subtask.py index 771e97649..999ba5795 100644 --- a/mpas_analysis/shared/climatology/remap_mpas_climatology_subtask.py +++ b/mpas_analysis/shared/climatology/remap_mpas_climatology_subtask.py @@ -58,6 +58,11 @@ class RemapMpasClimatologySubtask(AnalysisTask): # {{{ If ``comparisonGridName`` is not ``None``, the name of a restart file from which the MPAS mesh can be read. + useNcremap : bool, optional + Whether to use ncremap to do the remapping (the other option being + an internal python code that handles more grid types and extra + dimensions) + Authors ------- Xylar Asay-Davis @@ -65,7 +70,8 @@ class RemapMpasClimatologySubtask(AnalysisTask): # {{{ def __init__(self, mpasClimatologyTask, parentTask, climatologyName, variableList, seasons, comparisonGridNames=['latlon'], - iselValues=None, subtaskName='remapMpasClimatology'): + iselValues=None, subtaskName='remapMpasClimatology', + useNcremap=None): # {{{ ''' Construct the analysis task and adds it as a subtask of the @@ -104,6 +110,14 @@ def __init__(self, mpasClimatologyTask, parentTask, climatologyName, subtaskName : str, optional The name of the subtask + useNcremap : bool, optional + Whether to use ncremap to do the remapping (the other option being + an internal python code that handles more grid types and extra + dimensions). This defaults to the config option ``useNcremap`` + if it is not explicitly given. If a comparison grid other than + ``latlon`` is given, ncremap is not supported so this flag is set + to ``False``. + Authors ------- Xylar Asay-Davis @@ -133,6 +147,12 @@ def __init__(self, mpasClimatologyTask, parentTask, climatologyName, # correctly self._fillValue = -9.99999979021476795361e+33 + if useNcremap is None: + self.useNcremap = self.config.getboolean('climatology', + 'useNcremap') + else: + self.useNcremap = useNcremap + # }}} def setup_and_check(self): # {{{ @@ -511,16 +531,11 @@ def _remap(self, inFileName, outFileName, remapper, comparisonGridName): # no remapping is needed return - useNcremap = self.config.getboolean('climatology', 'useNcremap') - - if comparisonGridName != 'latlon': - # ncremap doesn't support grids other than lat/lon - useNcremap = False - renormalizationThreshold = self.config.getfloat( 'climatology', 'renormalizationThreshold') - if useNcremap: + # ncremap doesn't support grids other than lat/lon + if self.useNcremap and comparisonGridName == 'latlon': remapper.remap_file(inFileName=inFileName, outFileName=outFileName, overwrite=True, From 80206008ff3c27003a98d7207b446618bc9a2390 Mon Sep 17 00:00:00 2001 From: Luke Van Roekel Date: Wed, 7 Mar 2018 15:34:19 -0600 Subject: [PATCH 22/71] Adds ability to compare to ARGO data with depth This commit follows the SOSE level capability but compares globally to ARGO data from Roemmich-Gilson Argo Climatology. --- mpas_analysis/config.default | 70 +++ mpas_analysis/ocean/__init__.py | 2 + mpas_analysis/ocean/climatology_map_argo.py | 461 ++++++++++++++++++++ run_mpas_analysis | 5 + 4 files changed, 538 insertions(+) create mode 100644 mpas_analysis/ocean/climatology_map_argo.py diff --git a/mpas_analysis/config.default b/mpas_analysis/config.default index 5a5f93cfa..2a7632b2e 100644 --- a/mpas_analysis/config.default +++ b/mpas_analysis/config.default @@ -213,6 +213,7 @@ mhtSubdirectory = MHT meltSubdirectory = Melt soseSubdirectory = SOSE sshSubdirectory = SSH +argoSubdirectory = ARGO # first and last year of SST observational climatology (preferably one of the # two ranges given below) @@ -703,6 +704,41 @@ normArgsDifference = {'vmin': -2., 'vmax': 2.} # place the ticks automatically by default # colorbarTicksDifference = numpy.linspace(-2., 2., 9) +[climatologyMapArgoTemperature] +## options related to plotting climatology maps of Global +## potential temperature at various levels against +## reference model results and Roemmich-Gilson Argo Climatology + +# comparison grid(s) +comparisonGrids = ['latlon'] + +# Times for comparison times (Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, +# Nov, Dec, JFM, AMJ, JAS, OND, ANN) +seasons = ['ANN','JAS','JFM'] + +# list of depths in meters (positive up) at which to analyze, 'top' for the +# sea surface, 'bot' for the sea floor +depths = ['top', -25, -50, -100, -150, -200, -400, -800, -1500] + + +# colormap for model/observations +colormapNameResult = RdBu_r +# the type of norm used in the colormap +normTypeResult = linear +# A dictionary with keywords for the SemiLogNorm +normArgsResult = {'vmin': -2., 'vmax': 30.} +# place the ticks automatically by default +# colorbarTicksResult = numpy.linspace(-2., 2., 9) + +# colormap for differences +colormapNameDifference = RdBu_r +# the type of norm used in the colormap +normTypeDifference = linear +# A dictionary with keywords for the SemiLogNorm +normArgsDifference = {'vmin': -2., 'vmax': 2.} +# place the ticks automatically by default +# colorbarTicksDifference = numpy.linspace(-2., 2., 9) + [climatologyMapSoseSalinity] ## options related to plotting climatology maps of Antarctic ## salinity at various levels, including the sea floor against @@ -738,6 +774,40 @@ normArgsDifference = {'vmin': -0.5, 'vmax': 0.5} # place the ticks automatically by default # colorbarTicksDifference = numpy.linspace(-0.5, 0.5, 9) +[climatologyMapArgoSalinity] +## options related to plotting climatology maps of Global +## salinity at various levels against +## reference model results and the Roemmich-Gilson Argo Climatology + +# comparison grid(s) +comparisonGrids = ['latlon'] + +# Times for comparison times (Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, +# Nov, Dec, JFM, AMJ, JAS, OND, ANN) +seasons = ['ANN','JFM','JAS'] + +# list of depths in meters (positive up) at which to analyze, 'top' for the +# sea surface +depths = ['top', -25, -50, -100, -150, -200, -400, -600, -800, -1500] +#depths = ['top',-50] +# colormap for model/observations +colormapNameResult = BuOr +# the type of norm used in the colormap +normTypeResult = linear +# A dictionary with keywords for the SemiLogNorm +normArgsResult = {'vmin': 30, 'vmax': 39.0} +# place the ticks automatically by default +# colorbarTicksResult = numpy.linspace(34.2, 35.2, 9) + +# colormap for differences +colormapNameDifference = RdBu_r +# the type of norm used in the colormap +normTypeDifference = linear +# A dictionary with keywords for the SemiLogNorm +normArgsDifference = {'vmin': -0.5, 'vmax': 0.5} +# place the ticks automatically by default +# colorbarTicksDifference = numpy.linspace(-0.5, 0.5, 9) + [climatologyMapSeaIceConcNH] ## options related to plotting horizontally remapped climatologies of ## sea ice concentration against reference model results and observations diff --git a/mpas_analysis/ocean/__init__.py b/mpas_analysis/ocean/__init__.py index 359795fb5..f6f53384b 100644 --- a/mpas_analysis/ocean/__init__.py +++ b/mpas_analysis/ocean/__init__.py @@ -6,6 +6,8 @@ ClimatologyMapAntarcticMelt from mpas_analysis.ocean.climatology_map_sose import \ ClimatologyMapSoseTemperature, ClimatologyMapSoseSalinity +from mpas_analysis.ocean.climatology_map_argo import \ + ClimatologyMapArgoTemperature, ClimatologyMapArgoSalinity from mpas_analysis.ocean.time_series_temperature_anomaly import \ TimeSeriesTemperatureAnomaly diff --git a/mpas_analysis/ocean/climatology_map_argo.py b/mpas_analysis/ocean/climatology_map_argo.py new file mode 100644 index 000000000..e33b05b6a --- /dev/null +++ b/mpas_analysis/ocean/climatology_map_argo.py @@ -0,0 +1,461 @@ +''' +Analysis tasks for comparing Global climatology maps against ARGO data. + +Authors +------- +Luke Van Roekel +''' + +import xarray as xr +import numpy as np + +from mpas_analysis.shared import AnalysisTask + +from mpas_analysis.ocean.remap_depth_slices_subtask import \ + RemapDepthSlicesSubtask + +from mpas_analysis.ocean.plot_climatology_map_subtask import \ + PlotClimatologyMapSubtask + +from mpas_analysis.shared.io.utility import build_config_full_path + +from mpas_analysis.shared.climatology import RemapObservedClimatologySubtask, \ + RemapMpasClimatologySubtask + +from mpas_analysis.shared.grid import LatLonGridDescriptor + +from mpas_analysis.shared.mpas_xarray import mpas_xarray + + +class ClimatologyMapArgoTemperature(AnalysisTask): # {{{ + """ + An analysis task for comparison of antarctic temperature against SOSE + fields + + Authors + ------- + Luke Van Roekel, Xylar Asay-Davis + """ + + def __init__(self, config, mpasClimatologyTask, + refConfig=None): # {{{ + """ + Construct the analysis task. + + Parameters + ---------- + config : ``MpasAnalysisConfigParser`` + Configuration options + + mpasClimatologyTask : ``MpasClimatologyTask`` + The task that produced the climatology to be remapped and plotted + + refConfig : ``MpasAnalysisConfigParser``, optional + Configuration options for a reference run (if any) + + Authors + ------- + Luke Van Roekel, Xylar Asay-Davis + """ + fieldName = 'temperature' + # call the constructor from the base class (AnalysisTask) + super(ClimatologyMapArgoTemperature, self).__init__( + config=config, taskName='climatologyMapArgoTemperature', + componentName='ocean', + tags=['climatology', 'horizontalMap', 'argo', fieldName]) + + sectionName = self.taskName + + mpasFieldName = 'timeMonthly_avg_activeTracers_temperature' + iselValues = None + + # read in what seasons we want to plot + seasons = config.getExpression(sectionName, 'seasons') + + if len(seasons) == 0: + raise ValueError('config section {} does not contain valid list ' + 'of seasons'.format(sectionName)) + + comparisonGridNames = config.getExpression(sectionName, + 'comparisonGrids') + + if len(comparisonGridNames) == 0: + raise ValueError('config section {} does not contain valid list ' + 'of comparison grids'.format(sectionName)) + + depths = config.getExpression(sectionName, 'depths') + + if len(depths) == 0: + raise ValueError('config section {} does not contain valid ' + 'list of depths'.format(sectionName)) + + # the variable 'timeMonthly_avg_landIceFreshwaterFlux' will be added to + # mpasClimatologyTask along with the seasons. + remapClimatologySubtask = RemapDepthSlicesSubtask( + mpasClimatologyTask=mpasClimatologyTask, + parentTask=self, + climatologyName=fieldName, + variableList=[mpasFieldName], + seasons=seasons, + depths=depths, + comparisonGridNames=comparisonGridNames, + iselValues=iselValues) + + if refConfig is None: + + refTitleLabel = 'Roemmich-Gilson Argo Climatology: Temperature' + + observationsDirectory = build_config_full_path( + config, 'oceanObservations', 'argoSubdirectory') + + obsFileName = \ + '{}/ArgoClimatology_TS.nc'.format( + observationsDirectory) + refFieldName = 'theta' + outFileLabel = 'tempArgo' + galleryName = 'Roemmich-Gilson Climatology: ARGO' + diffTitleLabel = 'Model - Argo' + + remapObservationsSubtask = RemapArgoClimatology( + parentTask=self, seasons=seasons, fileName=obsFileName, + outFilePrefix=refFieldName, + fieldName=refFieldName, + depths=depths, + comparisonGridNames=comparisonGridNames) + + self.add_subtask(remapObservationsSubtask) + + else: + remapObservationsSubtask = None + refRunName = refConfig.get('runs', 'mainRunName') + galleryName = 'Ref: {}'.format(refRunName) + refTitleLabel = galleryName + + refFieldName = mpasFieldName + outFileLabel = 'temp' + diffTitleLabel = 'Main - Reference' + + for comparisonGridName in comparisonGridNames: + for season in seasons: + for depth in depths: + subtask = PlotClimatologyMapSubtask( + parentTask=self, + season=season, + comparisonGridName=comparisonGridName, + remapMpasClimatologySubtask=remapClimatologySubtask, + remapObsClimatologySubtask=remapObservationsSubtask, + refConfig=refConfig, + depth=depth) + + subtask.set_plot_info( + outFileLabel=outFileLabel, + fieldNameInTitle='Temperature', + mpasFieldName=mpasFieldName, + refFieldName=refFieldName, + refTitleLabel=refTitleLabel, + diffTitleLabel=diffTitleLabel, + unitsLabel=r'$^\circ$C', + imageCaption='Temperature', + galleryGroup='Temperature', + groupSubtitle=None, + groupLink='temp', + galleryName=galleryName) + + self.add_subtask(subtask) + # }}} + + # }}} + + +class ClimatologyMapArgoSalinity(AnalysisTask): # {{{ + """ + An analysis task for comparison of Global Temperature against Argo + fields + + Authors + ------- + Xylar Asay-Davis, Luke Van Roekel + """ + + def __init__(self, config, mpasClimatologyTask, + refConfig=None): # {{{ + """ + Construct the analysis task. + + Parameters + ---------- + config : ``MpasAnalysisConfigParser`` + Configuration options + + mpasClimatologyTask : ``MpasClimatologyTask`` + The task that produced the climatology to be remapped and plotted + + refConfig : ``MpasAnalysisConfigParser``, optional + Configuration options for a reference run (if any) + + Authors + ------- + Xylar Asay-Davis, Luke Van Roekel + """ + fieldName = 'salinity' + # call the constructor from the base class (AnalysisTask) + super(ClimatologyMapArgoSalinity, self).__init__( + config=config, taskName='climatologyMapArgoSalinity', + componentName='ocean', + tags=['climatology', 'horizontalMap', 'argo', fieldName]) + + sectionName = self.taskName + + mpasFieldName = 'timeMonthly_avg_activeTracers_salinity' + iselValues = None + + # read in what seasons we want to plot + seasons = config.getExpression(sectionName, 'seasons') + + if len(seasons) == 0: + raise ValueError('config section {} does not contain valid list ' + 'of seasons'.format(sectionName)) + + comparisonGridNames = config.getExpression(sectionName, + 'comparisonGrids') + + if len(comparisonGridNames) == 0: + raise ValueError('config section {} does not contain valid list ' + 'of comparison grids'.format(sectionName)) + + depths = config.getExpression(sectionName, 'depths') + + if len(depths) == 0: + raise ValueError('config section {} does not contain valid ' + 'list of depths'.format(sectionName)) + + # the variable 'timeMonthly_avg_landIceFreshwaterFlux' will be added to + # mpasClimatologyTask along with the seasons. + remapClimatologySubtask = RemapDepthSlicesSubtask( + mpasClimatologyTask=mpasClimatologyTask, + parentTask=self, + climatologyName=fieldName, + variableList=[mpasFieldName], + seasons=seasons, + depths=depths, + comparisonGridNames=comparisonGridNames, + iselValues=iselValues) + + if refConfig is None: + + refTitleLabel = 'Roemmich-Gilson Argo Climatology: Salinity' + + observationsDirectory = build_config_full_path( + config, 'oceanObservations', 'argoSubdirectory') + + obsFileName = \ + '{}/ArgoClimatology_TS.nc'.format( + observationsDirectory) + refFieldName = 'salinity' + outFileLabel = 'salinArgo' + galleryName = 'Roemmich-Gilson Climatology: Argo' + diffTitleLabel = 'Model - Argo' + + remapObservationsSubtask = RemapArgoClimatology( + parentTask=self, seasons=seasons, fileName=obsFileName, + outFilePrefix=refFieldName, + fieldName=refFieldName, + depths=depths, + comparisonGridNames=comparisonGridNames) + + self.add_subtask(remapObservationsSubtask) + + else: + remapObservationsSubtask = None + refRunName = refConfig.get('runs', 'mainRunName') + galleryName = None + refTitleLabel = 'Ref: {}'.format(refRunName) + + refFieldName = mpasFieldName + outFileLabel = 'salin' + diffTitleLabel = 'Main - Reference' + + for comparisonGridName in comparisonGridNames: + for season in seasons: + for depth in depths: + subtask = PlotClimatologyMapSubtask( + parentTask=self, + season=season, + comparisonGridName=comparisonGridName, + remapMpasClimatologySubtask=remapClimatologySubtask, + remapObsClimatologySubtask=remapObservationsSubtask, + refConfig=refConfig, + depth=depth) + + subtask.set_plot_info( + outFileLabel=outFileLabel, + fieldNameInTitle='Salinity', + mpasFieldName=mpasFieldName, + refFieldName=refFieldName, + refTitleLabel=refTitleLabel, + diffTitleLabel=diffTitleLabel, + unitsLabel=r'PSU', + imageCaption='Salinity', + galleryGroup='Salinity', + groupSubtitle=None, + groupLink='salin', + galleryName=galleryName) + + self.add_subtask(subtask) + # }}} + + # }}} + + +class RemapArgoClimatology(RemapObservedClimatologySubtask): + # {{{ + """ + A subtask for reading and remapping SOSE fields to the comparison grid + + Authors + ------- + Xylar Asay-Davis, Luke Van Roekel + """ + + def __init__(self, parentTask, seasons, fileName, outFilePrefix, + fieldName, depths, + comparisonGridNames=['latlon'], + subtaskName='remapObservations'): + # {{{ + ''' + Construct one analysis subtask for each plot (i.e. each season and + comparison grid) and a subtask for computing climatologies. + + Parameters + ---------- + parentTask : ``AnalysisTask`` + The parent (master) task for this subtask + + seasons : list of str + A list of seasons (keys in ``constants.monthDictionary``) over + which the climatology should be computed. + + fileName : str + The name of the observation file + + outFilePrefix : str + The prefix in front of output files and mapping files, typically + the name of the field being remapped + + fieldName : str + The name of the 3D field to remap + + depths : list of {None, float, 'top', 'bot'} + A list of depths at which the climatology will be sliced in the + vertical. + + comparisonGridNames : list of {'latlon', 'antarctic'}, optional + The name(s) of the comparison grid to use for remapping. + + subtaskName : str, optional + The name of the subtask + + Authors + ------- + Xylar Asay-Davis, Luke Van Roekel + + ''' + + self.fieldName = fieldName + self.depths = depths + + # call the constructor from the base class + # (RemapObservedClimatologySubtask) + super(RemapArgoClimatology, self).__init__( + parentTask, seasons, fileName, outFilePrefix, + comparisonGridNames, subtaskName) + # }}} + + def get_observation_descriptor(self, fileName): # {{{ + ''' + get a MeshDescriptor for the observation grid + + Parameters + ---------- + fileName : str + observation file name describing the source grid + + Returns + ------- + obsDescriptor : ``MeshDescriptor`` + The descriptor for the observation grid + + Authors + ------- + Xylar Asay-Davis, Luke Van Roekel + ''' + + # Load Argo observational Data + dsObs = self.build_observational_dataset(fileName) + + # create a descriptor of the observation grid using Lat/Lon + # coordinates + obsDescriptor = LatLonGridDescriptor.read(ds=dsObs, + latVarName='latCoord', + lonVarName='lonCoord') + dsObs.close() + return obsDescriptor # }}} + + def build_observational_dataset(self, fileName): # {{{ + ''' + read in the data sets for observations, and possibly rename some + variables and dimensions + + Parameters + ---------- + fileName : str + observation file name + + Returns + ------- + dsObs : ``xarray.Dataset`` + The observational dataset + + Authors + ------- + Xylar Asay-Davis, Luke Van Roekel + ''' + + # Load Argo observational data + dsObs = xr.open_dataset(fileName) + + # Rename coordinates to be consistent with other datasets + dsObs.rename({'month':'calmonth', 'LATITUDE': 'latCoord', + 'LONGITUDE':'lonCoord', 'DEPTH': 'depth'}, inplace=True) + dsObs.coords['LATITUDE'] = dsObs['latCoord'] + dsObs.coords['LONGITUDE'] = dsObs['lonCoord'] + dsObs.coords['DEPTH'] = dsObs['depth'] + dsObs.coords['month'] = ('Time', np.array(dsObs['calmonth'], int)) + + # no meaningful year since this is already a climatology + dsObs.coords['year'] = ('Time', np.ones(dsObs.dims['Time'], int)) + dsObs = mpas_xarray.subset_variables(dsObs, [self.fieldName, 'month']) + + slices = [] + field = dsObs[self.fieldName] + for depth in self.depths: + if depth == 'top': + slices.append(field.sel(method='nearest', depth=0.).drop( + 'depth')) + elif depth == 'bot': + slices.append(botField) + else: + slices.append(field.sel(method='nearest', depth=depth).drop( + 'depth')) + + depthNames = [str(depth) for depth in self.depths] + field = xr.concat(slices, dim='depthSlice') + + dsObs = xr.Dataset(data_vars={self.fieldName: field}, + coords={'depthSlice': depthNames}) + + return dsObs # }}} + + # }}} + +# vim: foldmethod=marker ai ts=4 sts=4 et sw=4 ft=python diff --git a/run_mpas_analysis b/run_mpas_analysis index 9c4aa4e1b..87d608229 100755 --- a/run_mpas_analysis +++ b/run_mpas_analysis @@ -91,6 +91,11 @@ def build_analysis_list(config, refConfig): # {{{ config, oceanClimatolgyTask, refConfig)) analyses.append(ocean.ClimatologyMapSoseSalinity( config, oceanClimatolgyTask, refConfig)) + analyses.append(ocean.ClimatologyMapArgoTemperature( + config, oceanClimatolgyTask, refConfig)) + analyses.append(ocean.ClimatologyMapArgoSalinity( + config, oceanClimatolgyTask, refConfig)) + analyses.append(ocean.ClimatologyMapAntarcticMelt(config, oceanClimatolgyTask, refConfig)) From 3cc66652a0038c97003b269f7a3c35381de2f815 Mon Sep 17 00:00:00 2001 From: Xylar Asay-Davis Date: Wed, 7 Mar 2018 17:46:43 -0600 Subject: [PATCH 23/71] Add support for specifying the anomaly ref year This is useful for runs that include a spin-up phase and anomalies are only of interest after the spin-up has completed (e.g. the last CORE-II cycle in a G-case E3SM run). --- mpas_analysis/config.default | 5 +++++ mpas_analysis/ocean/compute_anomaly_subtask.py | 8 ++++++-- .../shared/time_series/mpas_time_series_task.py | 15 ++++++++++----- 3 files changed, 21 insertions(+), 7 deletions(-) diff --git a/mpas_analysis/config.default b/mpas_analysis/config.default index 5a5f93cfa..dacd54d32 100644 --- a/mpas_analysis/config.default +++ b/mpas_analysis/config.default @@ -184,6 +184,11 @@ renormalizationThreshold = 0.01 ## options related to producing time series plots, often to compare against ## observations and previous runs +# the year from which to compute anomalies if not the start year of the +# simulation. This might be useful if a long spin-up cycle is performed and +# only the anomaly over a later span of years is of interest. +# anomalyRefYear = 249 + # start and end years for timeseries analysis. Using out-of-bounds values # like start_year = 1 and end_year = 9999 will be clipped to the valid range # of years, and is a good way of insuring that all values are used. diff --git a/mpas_analysis/ocean/compute_anomaly_subtask.py b/mpas_analysis/ocean/compute_anomaly_subtask.py index 49773a538..293ac7659 100644 --- a/mpas_analysis/ocean/compute_anomaly_subtask.py +++ b/mpas_analysis/ocean/compute_anomaly_subtask.py @@ -145,12 +145,16 @@ def run_task(self): # {{{ startDate = config.get('timeSeries', 'startDate') endDate = config.get('timeSeries', 'endDate') - simulationStartTime = get_simulation_start_time(self.runStreams) + if config.has_option('timeSeries', 'anomalyRefYear'): + anomalyYear = config.getint('timeSeries', 'anomalyRefYear') + anomalyRefDate = '{:04d}-01-01_00:00:00'.format(anomalyYear) + else: + anomalyRefDate = get_simulation_start_time(self.runStreams) ds = compute_moving_avg_anomaly_from_start( timeSeriesFileName=self.inputFile, variableList=self.variableList, - simulationStartTime=simulationStartTime, + simulationStartTime=anomalyRefDate, startDate=startDate, endDate=endDate, calendar=self.calendar, diff --git a/mpas_analysis/shared/time_series/mpas_time_series_task.py b/mpas_analysis/shared/time_series/mpas_time_series_task.py index 2c194415a..a6ef1fc1d 100644 --- a/mpas_analysis/shared/time_series/mpas_time_series_task.py +++ b/mpas_analysis/shared/time_series/mpas_time_series_task.py @@ -161,12 +161,17 @@ def setup_and_check(self): # {{{ os.path.basename(self.inputFiles[-1])) # Make sure first year of data is included for computing anomalies - simulationStartTime = get_simulation_start_time(self.runStreams) - firstYear = int(simulationStartTime[0:4]) - endDateFirstYear = '{:04d}-12-31_23:59:59'.format(firstYear) + if config.has_option('timeSeries', 'anomalyRefYear'): + anomalyYear = config.getint('timeSeries', 'anomalyRefYear') + anomalyStartDate = '{:04d}-01-01_00:00:00'.format(anomalyYear) + else: + anomalyStartDate = get_simulation_start_time(self.runStreams) + anomalyYear = int(anomalyStartDate[0:4]) + + anomalyEndDate = '{:04d}-12-31_23:59:59'.format(anomalyYear) firstYearInputFiles = self.historyStreams.readpath( - streamName, startDate=simulationStartTime, - endDate=endDateFirstYear, + streamName, startDate=anomalyStartDate, + endDate=anomalyEndDate, calendar=self.calendar) for fileName in firstYearInputFiles: if fileName not in self.inputFiles: From b477f1c6f623cd74d4f766474485751bbb638375 Mon Sep 17 00:00:00 2001 From: Luke Van Roekel Date: Thu, 8 Mar 2018 01:12:36 -0500 Subject: [PATCH 24/71] Fixes issue with remap file name the argo task caused an error when run with the SOSE task due to same name remap files and different depth slices --- mpas_analysis/ocean/climatology_map_argo.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/mpas_analysis/ocean/climatology_map_argo.py b/mpas_analysis/ocean/climatology_map_argo.py index e33b05b6a..724e8da1f 100644 --- a/mpas_analysis/ocean/climatology_map_argo.py +++ b/mpas_analysis/ocean/climatology_map_argo.py @@ -57,7 +57,7 @@ def __init__(self, config, mpasClimatologyTask, ------- Luke Van Roekel, Xylar Asay-Davis """ - fieldName = 'temperature' + fieldName = 'temperatureARGO' # call the constructor from the base class (AnalysisTask) super(ClimatologyMapArgoTemperature, self).__init__( config=config, taskName='climatologyMapArgoTemperature', @@ -155,8 +155,8 @@ def __init__(self, config, mpasClimatologyTask, refTitleLabel=refTitleLabel, diffTitleLabel=diffTitleLabel, unitsLabel=r'$^\circ$C', - imageCaption='Temperature', - galleryGroup='Temperature', + imageCaption='ARGO_Temperature', + galleryGroup='ARGO_Temperature', groupSubtitle=None, groupLink='temp', galleryName=galleryName) @@ -197,7 +197,7 @@ def __init__(self, config, mpasClimatologyTask, ------- Xylar Asay-Davis, Luke Van Roekel """ - fieldName = 'salinity' + fieldName = 'salinityARGO' # call the constructor from the base class (AnalysisTask) super(ClimatologyMapArgoSalinity, self).__init__( config=config, taskName='climatologyMapArgoSalinity', @@ -295,8 +295,8 @@ def __init__(self, config, mpasClimatologyTask, refTitleLabel=refTitleLabel, diffTitleLabel=diffTitleLabel, unitsLabel=r'PSU', - imageCaption='Salinity', - galleryGroup='Salinity', + imageCaption='ARGO_Salinity', + galleryGroup='ARGO_Salinity', groupSubtitle=None, groupLink='salin', galleryName=galleryName) From 8e63a93e88b094f9aa19862d4dd11b470db9b788 Mon Sep 17 00:00:00 2001 From: Luke Van Roekel Date: Thu, 8 Mar 2018 11:24:11 -0500 Subject: [PATCH 25/71] Changes formatting and variable naming for remap --- mpas_analysis/ocean/climatology_map_argo.py | 12 ++++++------ mpas_analysis/ocean/climatology_map_sose.py | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/mpas_analysis/ocean/climatology_map_argo.py b/mpas_analysis/ocean/climatology_map_argo.py index 724e8da1f..2eddda375 100644 --- a/mpas_analysis/ocean/climatology_map_argo.py +++ b/mpas_analysis/ocean/climatology_map_argo.py @@ -111,7 +111,7 @@ def __init__(self, config, mpasClimatologyTask, obsFileName = \ '{}/ArgoClimatology_TS.nc'.format( observationsDirectory) - refFieldName = 'theta' + refFieldName = 'thetaArgo' outFileLabel = 'tempArgo' galleryName = 'Roemmich-Gilson Climatology: ARGO' diffTitleLabel = 'Model - Argo' @@ -155,8 +155,8 @@ def __init__(self, config, mpasClimatologyTask, refTitleLabel=refTitleLabel, diffTitleLabel=diffTitleLabel, unitsLabel=r'$^\circ$C', - imageCaption='ARGO_Temperature', - galleryGroup='ARGO_Temperature', + imageCaption='Model temperature compared with ARGO observations', + galleryGroup='Argo Temperature', groupSubtitle=None, groupLink='temp', galleryName=galleryName) @@ -251,7 +251,7 @@ def __init__(self, config, mpasClimatologyTask, obsFileName = \ '{}/ArgoClimatology_TS.nc'.format( observationsDirectory) - refFieldName = 'salinity' + refFieldName = 'salinityArgo' outFileLabel = 'salinArgo' galleryName = 'Roemmich-Gilson Climatology: Argo' diffTitleLabel = 'Model - Argo' @@ -295,8 +295,8 @@ def __init__(self, config, mpasClimatologyTask, refTitleLabel=refTitleLabel, diffTitleLabel=diffTitleLabel, unitsLabel=r'PSU', - imageCaption='ARGO_Salinity', - galleryGroup='ARGO_Salinity', + imageCaption='Model Salinity compared with Argo observations', + galleryGroup='Argo Salinity', groupSubtitle=None, groupLink='salin', galleryName=galleryName) diff --git a/mpas_analysis/ocean/climatology_map_sose.py b/mpas_analysis/ocean/climatology_map_sose.py index ef23524ab..d3668947f 100644 --- a/mpas_analysis/ocean/climatology_map_sose.py +++ b/mpas_analysis/ocean/climatology_map_sose.py @@ -57,7 +57,7 @@ def __init__(self, config, mpasClimatologyTask, ------- Xylar Asay-Davis """ - fieldName = 'temperature' + fieldName = 'temperatureSOSE' # call the constructor from the base class (AnalysisTask) super(ClimatologyMapSoseTemperature, self).__init__( config=config, taskName='climatologyMapSoseTemperature', @@ -112,7 +112,7 @@ def __init__(self, config, mpasClimatologyTask, '{}/SOSE_2005-2010_monthly_pot_temp_6000.0x' \ '6000.0km_10.0km_Antarctic_stereo.nc'.format( observationsDirectory) - refFieldName = 'theta' + refFieldName = 'thetaSOSE' outFileLabel = 'tempSOSE' galleryName = 'State Estimate: SOSE' diffTitleLabel = 'Model - State Estimate' @@ -157,7 +157,7 @@ def __init__(self, config, mpasClimatologyTask, refTitleLabel=refTitleLabel, diffTitleLabel=diffTitleLabel, unitsLabel=r'$^\circ$C', - imageCaption='Temperature', + imageCaption='Temperature compared with SOSE', galleryGroup='Temperature', groupSubtitle=None, groupLink='temp', @@ -199,7 +199,7 @@ def __init__(self, config, mpasClimatologyTask, ------- Xylar Asay-Davis """ - fieldName = 'salinity' + fieldName = 'salinitySOSE' # call the constructor from the base class (AnalysisTask) super(ClimatologyMapSoseSalinity, self).__init__( config=config, taskName='climatologyMapSoseSalinity', @@ -254,7 +254,7 @@ def __init__(self, config, mpasClimatologyTask, '{}/SOSE_2005-2010_monthly_salinity_6000.0x' \ '6000.0km_10.0km_Antarctic_stereo.nc'.format( observationsDirectory) - refFieldName = 'salinity' + refFieldName = 'salinitySOSE' outFileLabel = 'salinSOSE' galleryName = 'State Estimate: SOSE' diffTitleLabel = 'Model - State Estimate' @@ -299,7 +299,7 @@ def __init__(self, config, mpasClimatologyTask, refTitleLabel=refTitleLabel, diffTitleLabel=diffTitleLabel, unitsLabel=r'PSU', - imageCaption='Salinity', + imageCaption='Salinity compared with SOSE', galleryGroup='Salinity', groupSubtitle=None, groupLink='salin', From e580a2470282bd8e22325b175ed4a84b729d2ffa Mon Sep 17 00:00:00 2001 From: Xylar Asay-Davis Date: Thu, 8 Mar 2018 10:50:55 -0700 Subject: [PATCH 26/71] Some formatting clean up and removing 'bot' Argo tasks don't (yet) support plotting the bottom T and S. --- mpas_analysis/config.default | 4 ++-- mpas_analysis/ocean/climatology_map_argo.py | 21 ++++++++++----------- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/mpas_analysis/config.default b/mpas_analysis/config.default index 2a7632b2e..fc567efc7 100644 --- a/mpas_analysis/config.default +++ b/mpas_analysis/config.default @@ -717,7 +717,7 @@ comparisonGrids = ['latlon'] seasons = ['ANN','JAS','JFM'] # list of depths in meters (positive up) at which to analyze, 'top' for the -# sea surface, 'bot' for the sea floor +# sea surface depths = ['top', -25, -50, -100, -150, -200, -400, -800, -1500] @@ -789,7 +789,7 @@ seasons = ['ANN','JFM','JAS'] # list of depths in meters (positive up) at which to analyze, 'top' for the # sea surface depths = ['top', -25, -50, -100, -150, -200, -400, -600, -800, -1500] -#depths = ['top',-50] + # colormap for model/observations colormapNameResult = BuOr # the type of norm used in the colormap diff --git a/mpas_analysis/ocean/climatology_map_argo.py b/mpas_analysis/ocean/climatology_map_argo.py index 2eddda375..e56c9c994 100644 --- a/mpas_analysis/ocean/climatology_map_argo.py +++ b/mpas_analysis/ocean/climatology_map_argo.py @@ -19,10 +19,9 @@ from mpas_analysis.shared.io.utility import build_config_full_path -from mpas_analysis.shared.climatology import RemapObservedClimatologySubtask, \ - RemapMpasClimatologySubtask +from mpas_analysis.shared.climatology import RemapObservedClimatologySubtask -from mpas_analysis.shared.grid import LatLonGridDescriptor +from mpas_analysis.shared.grid import LatLonGridDescriptor from mpas_analysis.shared.mpas_xarray import mpas_xarray @@ -155,7 +154,8 @@ def __init__(self, config, mpasClimatologyTask, refTitleLabel=refTitleLabel, diffTitleLabel=diffTitleLabel, unitsLabel=r'$^\circ$C', - imageCaption='Model temperature compared with ARGO observations', + imageCaption='Model temperature compared with ARGO ' + 'observations', galleryGroup='Argo Temperature', groupSubtitle=None, groupLink='temp', @@ -295,7 +295,8 @@ def __init__(self, config, mpasClimatologyTask, refTitleLabel=refTitleLabel, diffTitleLabel=diffTitleLabel, unitsLabel=r'PSU', - imageCaption='Model Salinity compared with Argo observations', + imageCaption='Model Salinity compared with Argo ' + 'observations', galleryGroup='Argo Salinity', groupSubtitle=None, groupLink='salin', @@ -345,7 +346,7 @@ def __init__(self, parentTask, seasons, fileName, outFilePrefix, fieldName : str The name of the 3D field to remap - depths : list of {None, float, 'top', 'bot'} + depths : list of {None, float, 'top'} A list of depths at which the climatology will be sliced in the vertical. @@ -393,7 +394,7 @@ def get_observation_descriptor(self, fileName): # {{{ # Load Argo observational Data dsObs = self.build_observational_dataset(fileName) - # create a descriptor of the observation grid using Lat/Lon + # create a descriptor of the observation grid using Lat/Lon # coordinates obsDescriptor = LatLonGridDescriptor.read(ds=dsObs, latVarName='latCoord', @@ -425,8 +426,8 @@ def build_observational_dataset(self, fileName): # {{{ dsObs = xr.open_dataset(fileName) # Rename coordinates to be consistent with other datasets - dsObs.rename({'month':'calmonth', 'LATITUDE': 'latCoord', - 'LONGITUDE':'lonCoord', 'DEPTH': 'depth'}, inplace=True) + dsObs.rename({'month': 'calmonth', 'LATITUDE': 'latCoord', + 'LONGITUDE': 'lonCoord', 'DEPTH': 'depth'}, inplace=True) dsObs.coords['LATITUDE'] = dsObs['latCoord'] dsObs.coords['LONGITUDE'] = dsObs['lonCoord'] dsObs.coords['DEPTH'] = dsObs['depth'] @@ -442,8 +443,6 @@ def build_observational_dataset(self, fileName): # {{{ if depth == 'top': slices.append(field.sel(method='nearest', depth=0.).drop( 'depth')) - elif depth == 'bot': - slices.append(botField) else: slices.append(field.sel(method='nearest', depth=depth).drop( 'depth')) From cd66abe8200ab2c6c4d95c66a3b800d23193492d Mon Sep 17 00:00:00 2001 From: Xylar Asay-Davis Date: Thu, 8 Mar 2018 11:09:11 -0700 Subject: [PATCH 27/71] Fix SOSE and ARGO obs. field names Should the field names should be unchanged, but the file prefix should include SOSE or ARGO. --- mpas_analysis/ocean/climatology_map_argo.py | 8 ++++---- mpas_analysis/ocean/climatology_map_sose.py | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/mpas_analysis/ocean/climatology_map_argo.py b/mpas_analysis/ocean/climatology_map_argo.py index e56c9c994..17af5996c 100644 --- a/mpas_analysis/ocean/climatology_map_argo.py +++ b/mpas_analysis/ocean/climatology_map_argo.py @@ -110,14 +110,14 @@ def __init__(self, config, mpasClimatologyTask, obsFileName = \ '{}/ArgoClimatology_TS.nc'.format( observationsDirectory) - refFieldName = 'thetaArgo' + refFieldName = 'theta' outFileLabel = 'tempArgo' galleryName = 'Roemmich-Gilson Climatology: ARGO' diffTitleLabel = 'Model - Argo' remapObservationsSubtask = RemapArgoClimatology( parentTask=self, seasons=seasons, fileName=obsFileName, - outFilePrefix=refFieldName, + outFilePrefix='{}Argo'.format(refFieldName), fieldName=refFieldName, depths=depths, comparisonGridNames=comparisonGridNames) @@ -251,14 +251,14 @@ def __init__(self, config, mpasClimatologyTask, obsFileName = \ '{}/ArgoClimatology_TS.nc'.format( observationsDirectory) - refFieldName = 'salinityArgo' + refFieldName = 'salinity' outFileLabel = 'salinArgo' galleryName = 'Roemmich-Gilson Climatology: Argo' diffTitleLabel = 'Model - Argo' remapObservationsSubtask = RemapArgoClimatology( parentTask=self, seasons=seasons, fileName=obsFileName, - outFilePrefix=refFieldName, + outFilePrefix='{}Argo'.format(refFieldName), fieldName=refFieldName, depths=depths, comparisonGridNames=comparisonGridNames) diff --git a/mpas_analysis/ocean/climatology_map_sose.py b/mpas_analysis/ocean/climatology_map_sose.py index d3668947f..53a626622 100644 --- a/mpas_analysis/ocean/climatology_map_sose.py +++ b/mpas_analysis/ocean/climatology_map_sose.py @@ -112,14 +112,14 @@ def __init__(self, config, mpasClimatologyTask, '{}/SOSE_2005-2010_monthly_pot_temp_6000.0x' \ '6000.0km_10.0km_Antarctic_stereo.nc'.format( observationsDirectory) - refFieldName = 'thetaSOSE' + refFieldName = 'theta' outFileLabel = 'tempSOSE' galleryName = 'State Estimate: SOSE' diffTitleLabel = 'Model - State Estimate' remapObservationsSubtask = RemapSoseClimatology( parentTask=self, seasons=seasons, fileName=obsFileName, - outFilePrefix=refFieldName, + outFilePrefix='{}SOSE'.format(refFieldName), fieldName=refFieldName, botFieldName='botTheta', depths=depths, @@ -254,14 +254,14 @@ def __init__(self, config, mpasClimatologyTask, '{}/SOSE_2005-2010_monthly_salinity_6000.0x' \ '6000.0km_10.0km_Antarctic_stereo.nc'.format( observationsDirectory) - refFieldName = 'salinitySOSE' + refFieldName = 'salinity' outFileLabel = 'salinSOSE' galleryName = 'State Estimate: SOSE' diffTitleLabel = 'Model - State Estimate' remapObservationsSubtask = RemapSoseClimatology( parentTask=self, seasons=seasons, fileName=obsFileName, - outFilePrefix=refFieldName, + outFilePrefix='{}SOSE'.format(refFieldName), fieldName=refFieldName, botFieldName='botSalinity', depths=depths, From 08e3c4beaee75b33165389caddba58109be21ec7 Mon Sep 17 00:00:00 2001 From: Xylar Asay-Davis Date: Thu, 8 Mar 2018 11:25:17 -0700 Subject: [PATCH 28/71] Fix group links --- mpas_analysis/ocean/climatology_map_argo.py | 4 ++-- mpas_analysis/ocean/climatology_map_sose.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/mpas_analysis/ocean/climatology_map_argo.py b/mpas_analysis/ocean/climatology_map_argo.py index 17af5996c..c8b625a81 100644 --- a/mpas_analysis/ocean/climatology_map_argo.py +++ b/mpas_analysis/ocean/climatology_map_argo.py @@ -158,7 +158,7 @@ def __init__(self, config, mpasClimatologyTask, 'observations', galleryGroup='Argo Temperature', groupSubtitle=None, - groupLink='temp', + groupLink='tempArgo', galleryName=galleryName) self.add_subtask(subtask) @@ -299,7 +299,7 @@ def __init__(self, config, mpasClimatologyTask, 'observations', galleryGroup='Argo Salinity', groupSubtitle=None, - groupLink='salin', + groupLink='salinArgo', galleryName=galleryName) self.add_subtask(subtask) diff --git a/mpas_analysis/ocean/climatology_map_sose.py b/mpas_analysis/ocean/climatology_map_sose.py index 53a626622..17b349e39 100644 --- a/mpas_analysis/ocean/climatology_map_sose.py +++ b/mpas_analysis/ocean/climatology_map_sose.py @@ -160,7 +160,7 @@ def __init__(self, config, mpasClimatologyTask, imageCaption='Temperature compared with SOSE', galleryGroup='Temperature', groupSubtitle=None, - groupLink='temp', + groupLink='tempSose', galleryName=galleryName) self.add_subtask(subtask) @@ -302,7 +302,7 @@ def __init__(self, config, mpasClimatologyTask, imageCaption='Salinity compared with SOSE', galleryGroup='Salinity', groupSubtitle=None, - groupLink='salin', + groupLink='salinSose', galleryName=galleryName) self.add_subtask(subtask) From c664fb4f978ad158c603012d090d025930f48dde Mon Sep 17 00:00:00 2001 From: Xylar Asay-Davis Date: Thu, 8 Mar 2018 12:38:38 -0800 Subject: [PATCH 29/71] State max depth of ARGO data --- mpas_analysis/config.default | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mpas_analysis/config.default b/mpas_analysis/config.default index fc567efc7..8a4fe64f9 100644 --- a/mpas_analysis/config.default +++ b/mpas_analysis/config.default @@ -717,7 +717,7 @@ comparisonGrids = ['latlon'] seasons = ['ANN','JAS','JFM'] # list of depths in meters (positive up) at which to analyze, 'top' for the -# sea surface +# sea surface. Argo data is only available above -2000 m depths = ['top', -25, -50, -100, -150, -200, -400, -800, -1500] @@ -787,7 +787,7 @@ comparisonGrids = ['latlon'] seasons = ['ANN','JFM','JAS'] # list of depths in meters (positive up) at which to analyze, 'top' for the -# sea surface +# sea surface. Argo data is only available above -2000 m depths = ['top', -25, -50, -100, -150, -200, -400, -600, -800, -1500] # colormap for model/observations From 861d41399dea898e3c1658ed7cca8a35da64f058 Mon Sep 17 00:00:00 2001 From: Xylar Asay-Davis Date: Sat, 25 Mar 2017 21:16:08 +0100 Subject: [PATCH 30/71] Make mpas_analysis an installable package --- docs/conf.py | 2 +- setup.cfg | 5 +++++ setup.py | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 setup.cfg create mode 100755 setup.py diff --git a/docs/conf.py b/docs/conf.py index d9a7031e7..0ebe5270d 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -57,7 +57,7 @@ # General information about the project. project = u'MPAS-Analysis' -copyright = u'2016-2017, Los Alamos National Security, LLC (LANS) (Ocean: ' \ +copyright = u'2016-2018, Los Alamos National Security, LLC (LANS) (Ocean: ' \ u'LA-CC-13-047; Land Ice: LA-CC-13-117) and the University ' \ u'Corporation for Atmospheric Research (UCAR)' author = u'Xylar Asay-Davis, Milena Veneziani, Phillip Wolfram, ' \ diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 000000000..44b0d881c --- /dev/null +++ b/setup.cfg @@ -0,0 +1,5 @@ +[wheel] +universal = 1 + +[tool:pytest] +python_files=test_*.py diff --git a/setup.py b/setup.py new file mode 100755 index 000000000..43f3c2e28 --- /dev/null +++ b/setup.py @@ -0,0 +1,46 @@ +#!/usr/bin/env python + +from setuptools import setup, find_packages +import warnings + +isrelease = True + +version = '0.7.0' + +if not isrelease: + import subprocess + try: + pipe = subprocess.Popen( + ["git", "describe", "--always", "--match", "v[0-9]*"], + stdout=subprocess.PIPE) + (version, stderr) = pipe.communicate() + except: + warnings.warn("WARNING: Couldn't get git revision, using generic " + "version string") + +setup(name='mpas_analysis', + version=version, + description='Analysis for Model for Prediction Across Scales (MPAS) ' + 'simulations.', + url='https://github.com/MPAS-Dev/MPAS-Analysis', + author='MPAS-Analysis Developers', + author_email='mpas-developers@googlegroups.com', + license='BSD', + classifiers=[ + 'Development Status :: 3 - Alpha', + 'License :: OSI Approved :: BSD License', + 'Operating System :: OS Independent', + 'Intended Audience :: Science/Research', + 'Programming Language :: Python', + 'Programming Language :: Python :: 2', + 'Programming Language :: Python :: 2.7', + 'Topic :: Scientific/Engineering', + ], + packages=find_packages(), + package_data={'mpas_analysis': ['config.default'], + 'mpas_analysis.shared.html': ['templates/*'], + 'mpas_analysis.test': ['test*/*', 'test*/*/*']}, + install_requires=['numpy', 'scipy', 'matplotlib', 'netCDF4', 'xarray', + 'dask', 'bottleneck', 'basemap', 'lxml', 'nco', + ' pyproj', 'pillow'], + scripts=['run_mpas_analysis']) From 7983de07afafcb17f9ffe1f907ffa8f6e530d43f Mon Sep 17 00:00:00 2001 From: Charles Doutriaux Date: Fri, 15 Sep 2017 09:48:55 -0700 Subject: [PATCH 31/71] adding conda recipe removing dependencies from setup install script, letting conda deal with it (for now) --- conda/recipe/build.sh | 2 ++ conda/recipe/meta.yaml | 47 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+) create mode 100644 conda/recipe/build.sh create mode 100644 conda/recipe/meta.yaml diff --git a/conda/recipe/build.sh b/conda/recipe/build.sh new file mode 100644 index 000000000..383455d82 --- /dev/null +++ b/conda/recipe/build.sh @@ -0,0 +1,2 @@ +#!/usr/bin/sh +python setup.py install --single-version-externally-managed --record=record.txt diff --git a/conda/recipe/meta.yaml b/conda/recipe/meta.yaml new file mode 100644 index 000000000..5b05b7b3c --- /dev/null +++ b/conda/recipe/meta.yaml @@ -0,0 +1,47 @@ +{% set version = "0.7.0" %} + +package: + name: mpas_analysis + version: {{ version }} + +source: + path: ../.. + +build: + number: 0 + +test: + requires: + - pytest + imports: + - mpas_analysis + - pytest + commands: + - pytest --pyargs mpas_analysis + +requirements: + build: + - python + - setuptools + run: + - python + - numpy + - scipy + - matplotlib + - netcdf4 + - xarray >=0.10.0 + - dask + - bottleneck + - basemap + - lxml + - nco >=4.7.0 + - pillow + +about: + home: http://gitub.com/MPAS-Dev/MPAS-Analysis + +extra: + recipe-maintainers: + - doutriaux1 + - xylar + From f4fccf2889900aedf8fd4e648970517b7f9bf684 Mon Sep 17 00:00:00 2001 From: Xylar Asay-Davis Date: Mon, 30 Oct 2017 13:25:08 -0600 Subject: [PATCH 32/71] Add licenses and code for adding licenses to source --- LICENSE | 39 ++++ licenses/A-PRIME_LICENSE.txt | 29 +++ licenses/NUMPY_LICENSE.txt | 30 +++ licenses/SEMENOV_LICENSE | 20 ++ licenses/XARRAY_LICENSE.txt | 191 +++++++++++++++++++ licenses/_headers/README.md | 91 +++++++++ licenses/_headers/header-css | 10 + licenses/_headers/header-css-full | 43 +++++ licenses/_headers/header-html | 10 + licenses/_headers/header-html-full | 43 +++++ licenses/_headers/header-ncl | 7 + licenses/_headers/header-ncl-full | 39 ++++ licenses/_headers/header-py | 7 + licenses/_headers/header-py-full | 39 ++++ licenses/_headers/license-bump-copyright.sh | 66 +++++++ licenses/_headers/license-find-missing.sh | 21 ++ licenses/_headers/license-prepend-missing.sh | 111 +++++++++++ licenses/_headers/license-setup.sh | 30 +++ 18 files changed, 826 insertions(+) create mode 100644 LICENSE create mode 100644 licenses/A-PRIME_LICENSE.txt create mode 100644 licenses/NUMPY_LICENSE.txt create mode 100644 licenses/SEMENOV_LICENSE create mode 100644 licenses/XARRAY_LICENSE.txt create mode 100755 licenses/_headers/README.md create mode 100755 licenses/_headers/header-css create mode 100755 licenses/_headers/header-css-full create mode 100755 licenses/_headers/header-html create mode 100755 licenses/_headers/header-html-full create mode 100755 licenses/_headers/header-ncl create mode 100755 licenses/_headers/header-ncl-full create mode 100755 licenses/_headers/header-py create mode 100755 licenses/_headers/header-py-full create mode 100755 licenses/_headers/license-bump-copyright.sh create mode 100755 licenses/_headers/license-find-missing.sh create mode 100755 licenses/_headers/license-prepend-missing.sh create mode 100755 licenses/_headers/license-setup.sh diff --git a/LICENSE b/LICENSE new file mode 100644 index 000000000..14f6b63cb --- /dev/null +++ b/LICENSE @@ -0,0 +1,39 @@ +Copyright (c) 2013, Los Alamos National Security, LLC (LANS) (Ocean: LA-CC-13-047; +Land Ice: LA-CC-13-117) and the University Corporation for Atmospheric Research (UCAR). + +All rights reserved. + +LANS is the operator of the Los Alamos National Laboratory under Contract No. +DE-AC52-06NA25396 with the U.S. Department of Energy. UCAR manages the National +Center for Atmospheric Research under Cooperative Agreement ATM-0753581 with the +National Science Foundation. The U.S. Government has rights to use, reproduce, +and distribute this software. NO WARRANTY, EXPRESS OR IMPLIED IS OFFERED BY +LANS, UCAR OR THE GOVERNMENT AND NONE OF THEM ASSUME ANY LIABILITY FOR THE USE +OF THIS SOFTWARE. If software is modified to produce derivative works, such +modified software should be clearly marked, so as not to confuse it with the +version available from LANS and UCAR. + +Additionally, redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1) Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2) Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +3) None of the names of LANS, UCAR or the names of its contributors, if any, may +be used to endorse or promote products derived from this software without +specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/licenses/A-PRIME_LICENSE.txt b/licenses/A-PRIME_LICENSE.txt new file mode 100644 index 000000000..27580e38b --- /dev/null +++ b/licenses/A-PRIME_LICENSE.txt @@ -0,0 +1,29 @@ +Copyright (c) 2017, UT-BATTELLE, LLC +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + diff --git a/licenses/NUMPY_LICENSE.txt b/licenses/NUMPY_LICENSE.txt new file mode 100644 index 000000000..906c7b536 --- /dev/null +++ b/licenses/NUMPY_LICENSE.txt @@ -0,0 +1,30 @@ +Copyright (c) 2005-2017, NumPy Developers. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + + * Neither the name of the NumPy Developers nor the names of any + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/licenses/SEMENOV_LICENSE b/licenses/SEMENOV_LICENSE new file mode 100644 index 000000000..ae576c8ce --- /dev/null +++ b/licenses/SEMENOV_LICENSE @@ -0,0 +1,20 @@ +Copyright (c) 2017 by Dmitry Semenov (https://codepen.io/dimsemenov/pen/ZYbPJM) + + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/licenses/XARRAY_LICENSE.txt b/licenses/XARRAY_LICENSE.txt new file mode 100644 index 000000000..37ec93a14 --- /dev/null +++ b/licenses/XARRAY_LICENSE.txt @@ -0,0 +1,191 @@ +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and +distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright +owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities +that control, are controlled by, or are under common control with that entity. +For the purposes of this definition, "control" means (i) the power, direct or +indirect, to cause the direction or management of such entity, whether by +contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the +outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising +permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including +but not limited to software source code, documentation source, and configuration +files. + +"Object" form shall mean any form resulting from mechanical transformation or +translation of a Source form, including but not limited to compiled object code, +generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made +available under the License, as indicated by a copyright notice that is included +in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that +is based on (or derived from) the Work and for which the editorial revisions, +annotations, elaborations, or other modifications represent, as a whole, an +original work of authorship. For the purposes of this License, Derivative Works +shall not include works that remain separable from, or merely link (or bind by +name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version +of the Work and any modifications or additions to that Work or Derivative Works +thereof, that is intentionally submitted to Licensor for inclusion in the Work +by the copyright owner or by an individual or Legal Entity authorized to submit +on behalf of the copyright owner. For the purposes of this definition, +"submitted" means any form of electronic, verbal, or written communication sent +to the Licensor or its representatives, including but not limited to +communication on electronic mailing lists, source code control systems, and +issue tracking systems that are managed by, or on behalf of, the Licensor for +the purpose of discussing and improving the Work, but excluding communication +that is conspicuously marked or otherwise designated in writing by the copyright +owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf +of whom a Contribution has been received by Licensor and subsequently +incorporated within the Work. + +2. Grant of Copyright License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable copyright license to reproduce, prepare Derivative Works of, +publicly display, publicly perform, sublicense, and distribute the Work and such +Derivative Works in Source or Object form. + +3. Grant of Patent License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable (except as stated in this section) patent license to make, have +made, use, offer to sell, sell, import, and otherwise transfer the Work, where +such license applies only to those patent claims licensable by such Contributor +that are necessarily infringed by their Contribution(s) alone or by combination +of their Contribution(s) with the Work to which such Contribution(s) was +submitted. If You institute patent litigation against any entity (including a +cross-claim or counterclaim in a lawsuit) alleging that the Work or a +Contribution incorporated within the Work constitutes direct or contributory +patent infringement, then any patent licenses granted to You under this License +for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. + +You may reproduce and distribute copies of the Work or Derivative Works thereof +in any medium, with or without modifications, and in Source or Object form, +provided that You meet the following conditions: + +You must give any other recipients of the Work or Derivative Works a copy of +this License; and +You must cause any modified files to carry prominent notices stating that You +changed the files; and +You must retain, in the Source form of any Derivative Works that You distribute, +all copyright, patent, trademark, and attribution notices from the Source form +of the Work, excluding those notices that do not pertain to any part of the +Derivative Works; and +If the Work includes a "NOTICE" text file as part of its distribution, then any +Derivative Works that You distribute must include a readable copy of the +attribution notices contained within such NOTICE file, excluding those notices +that do not pertain to any part of the Derivative Works, in at least one of the +following places: within a NOTICE text file distributed as part of the +Derivative Works; within the Source form or documentation, if provided along +with the Derivative Works; or, within a display generated by the Derivative +Works, if and wherever such third-party notices normally appear. The contents of +the NOTICE file are for informational purposes only and do not modify the +License. You may add Your own attribution notices within Derivative Works that +You distribute, alongside or as an addendum to the NOTICE text from the Work, +provided that such additional attribution notices cannot be construed as +modifying the License. +You may add Your own copyright statement to Your modifications and may provide +additional or different license terms and conditions for use, reproduction, or +distribution of Your modifications, or for any such Derivative Works as a whole, +provided Your use, reproduction, and distribution of the Work otherwise complies +with the conditions stated in this License. + +5. Submission of Contributions. + +Unless You explicitly state otherwise, any Contribution intentionally submitted +for inclusion in the Work by You to the Licensor shall be under the terms and +conditions of this License, without any additional terms or conditions. +Notwithstanding the above, nothing herein shall supersede or modify the terms of +any separate license agreement you may have executed with Licensor regarding +such Contributions. + +6. Trademarks. + +This License does not grant permission to use the trade names, trademarks, +service marks, or product names of the Licensor, except as required for +reasonable and customary use in describing the origin of the Work and +reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. + +Unless required by applicable law or agreed to in writing, Licensor provides the +Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, +including, without limitation, any warranties or conditions of TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are +solely responsible for determining the appropriateness of using or +redistributing the Work and assume any risks associated with Your exercise of +permissions under this License. + +8. Limitation of Liability. + +In no event and under no legal theory, whether in tort (including negligence), +contract, or otherwise, unless required by applicable law (such as deliberate +and grossly negligent acts) or agreed to in writing, shall any Contributor be +liable to You for damages, including any direct, indirect, special, incidental, +or consequential damages of any character arising as a result of this License or +out of the use or inability to use the Work (including but not limited to +damages for loss of goodwill, work stoppage, computer failure or malfunction, or +any and all other commercial damages or losses), even if such Contributor has +been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. + +While redistributing the Work or Derivative Works thereof, You may choose to +offer, and charge a fee for, acceptance of support, warranty, indemnity, or +other liability obligations and/or rights consistent with this License. However, +in accepting such obligations, You may act only on Your own behalf and on Your +sole responsibility, not on behalf of any other Contributor, and only if You +agree to indemnify, defend, and hold each Contributor harmless for any liability +incurred by, or claims asserted against, such Contributor by reason of your +accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work + +To apply the Apache License to your work, attach the following boilerplate +notice, with the fields enclosed by brackets "[]" replaced with your own +identifying information. (Don't include the brackets!) The text should be +enclosed in the appropriate comment syntax for the file format. We also +recommend that a file or class name and description of purpose be included on +the same "printed page" as the copyright notice for easier identification within +third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/licenses/_headers/README.md b/licenses/_headers/README.md new file mode 100755 index 000000000..79cd62ef9 --- /dev/null +++ b/licenses/_headers/README.md @@ -0,0 +1,91 @@ +# License Header Tools + +Before releasing software, it's important to ensure each "code" file has a license header, and that +header has an appropriate copyright date. Provided here are two main `bash` scripts to assist +developers in adding and updating the header files. + +* `license-prepend-missing.sh` finds "code" files which do not have a license header, and prepends + the relevant license header to the file. + + *Warning: Matlab uses the header of the file for its automatic help text. For Matlab files, + license files need to be appended to the file, or removed from the distribution entirely (LIVVkit + opted for the latter).* + +* `license-bump-copyright.sh` will find outdated copyright date statements, and replace them + (in place) with a current copyright statement. + +## Usage + +### `license-prepend-missing.sh` + +The `license-prepend-missing.sh` script will prepend a license header from a template to files with +these extensions: + +| Extension | Template file | +| --------- | ------------- | +| `.py` | `header-py` | +| `.sh` | `header-py` | +| `.bash` | `header-py` | +| `.html` | `header-html`| +| `.css` | `header-css` | +| `.js` | `header-css` | +| `.ncl` | `header-ncl` | + +*Note: Because comment syntax differs between these file types, files mush have one of the above +extensions --- extension-less files, and files without the above extensions are ignored.* + +This script work by first sourcing `license-setup.sh`, which sets the important search variables: + +* `SOURCE_DIR` sets the top level of the source repository, relative to the current working + directory. Currently, this is set as `../..` assuming the scripts will be run from this directory + (`docs/headers`). + +* `CURRENT` is a string that should be unique to the license header (e.g., `Copyright (c)`) and is + used to determine if the header is present in a file. + +* `ALWAYS_IGNORE` contains a set of regular expressions to match files which should always be + ignored by the find command (e.g., `*.git/*`). + +* `FILE_IGNORE` contains a set of regular expressions to match the types of files that don't need a + license header (e.g., `*.png`, `*.md`). + +* `PYTHON_IGNORE` contains a set of regular expressions to match python files which don't need a + license header, or are repackaged and licensed separately. + +* `CSS_IGNORE` contains a set of regular expressions to match web (CSS, Javascript, HTML) files + which don't need a license header, or are repackaged and licensed separately. + +The `license-prepend-missing.sh` script then goes through a number of find-and-modify blocks for +the above extensions, and appends a license header to the files missing a header. + +**Before** running the `license-prepend-missing.sh` script, it's important to ensure that the script +is finding the correct files. + +**First**, run the `license-find-missing.sh` script to verify the found files, which will output a list +of files without a license header. + +**Read through this output carefully!** This find command is generous and not restricted to the +above extensions. Files found with extensions differing from the list above will either need to be +added to the appropriate `*_IGNORE` variables in `license-setup.sh`, or added to the appropriate +find-and-modify block in `license-prepend-missing.sh` (or have a header added to it manually). *If +this file type's comment syntax differs from those found in the available templates, a new template +will need to be created and a new find-and-modify block added to `license-prepend-missing.sh`.* + +Once you're confident the `license-find-missing.sh` script is finding all the appropriate files, and +`license-prepend-missing.sh` has all the required find-and-modify blocks, simply run the +`liscense-prepend-missing.sh` script. You should now see a license header at the top of all your +"code" files. + +### `license-bump-copyright.sh` + +This script also uses the `*_IGNORE` variables from `license-setup.sh`, but instead of using the +`CURRENT` string to determine if a license header is present, it looks for the `OLD` string, which +is more restrictive, and replaces it (in place) with the `NEW` string. + +For example, `CURRENT` is typically set as `Copyright (c)`, which will match files with any copyright +statement, while `OLD` may be set as `Copyright (c) 2015, UT` to match files with the 2015 +copyright statement and `NEW` would set to `Copyright (c) 2015,2016, UT` to add 2016 to the +copyright statement. (`OLD` and `NEW` are found in `license-bump-copyright.sh`.) + +*Note: Like `license-find-missing.sh`, this script is not restricted to the above file types that +`license-prepend-missing.sh` is.* diff --git a/licenses/_headers/header-css b/licenses/_headers/header-css new file mode 100755 index 000000000..76537fd01 --- /dev/null +++ b/licenses/_headers/header-css @@ -0,0 +1,10 @@ +/* +/ Copyright (c) 2017, Los Alamos National Security, LLC (LANS) +/ and the University Corporation for Atmospheric Research (UCAR). +/ +/ Unless noted otherwise source code is licensed under the BSD license. +/ Additional copyright and license information can be found in the LICENSE file +/ distributed with this code, or at http://mpas-dev.github.com/license.html +/ */ + + diff --git a/licenses/_headers/header-css-full b/licenses/_headers/header-css-full new file mode 100755 index 000000000..e0069d034 --- /dev/null +++ b/licenses/_headers/header-css-full @@ -0,0 +1,43 @@ +/* +/ Copyright (c) 2017, Los Alamos National Security, LLC (LANS) (Ocean: LA-CC-13-047; +/ Land Ice: LA-CC-13-117) and the University Corporation for Atmospheric Research (UCAR). +/ +/ All rights reserved. +/ +/ LANS is the operator of the Los Alamos National Laboratory under Contract No. +/ DE-AC52-06NA25396 with the U.S. Department of Energy. UCAR manages the National +/ Center for Atmospheric Research under Cooperative Agreement ATM-0753581 with the +/ National Science Foundation. The U.S. Government has rights to use, reproduce, +/ and distribute this software. NO WARRANTY, EXPRESS OR IMPLIED IS OFFERED BY +/ LANS, UCAR OR THE GOVERNMENT AND NONE OF THEM ASSUME ANY LIABILITY FOR THE USE +/ OF THIS SOFTWARE. If software is modified to produce derivative works, such +/ modified software should be clearly marked, so as not to confuse it with the +/ version available from LANS and UCAR. +/ +/ Additionally, redistribution and use in source and binary forms, with or without +/ modification, are permitted provided that the following conditions are met: +/ +/ 1) Redistributions of source code must retain the above copyright notice, this +/ list of conditions and the following disclaimer. +/ +/ 2) Redistributions in binary form must reproduce the above copyright notice, +/ this list of conditions and the following disclaimer in the documentation and/or +/ other materials provided with the distribution. +/ +/ 3) None of the names of LANS, UCAR or the names of its contributors, if any, may +/ be used to endorse or promote products derived from this software without +/ specific prior written permission. +/ +/ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +/ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +/ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +/ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +/ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +/ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +/ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +/ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +/ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +/ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/ */ + + diff --git a/licenses/_headers/header-html b/licenses/_headers/header-html new file mode 100755 index 000000000..49114d2ef --- /dev/null +++ b/licenses/_headers/header-html @@ -0,0 +1,10 @@ + + + diff --git a/licenses/_headers/header-html-full b/licenses/_headers/header-html-full new file mode 100755 index 000000000..83a6f953e --- /dev/null +++ b/licenses/_headers/header-html-full @@ -0,0 +1,43 @@ + + + diff --git a/licenses/_headers/header-ncl b/licenses/_headers/header-ncl new file mode 100755 index 000000000..d501babe7 --- /dev/null +++ b/licenses/_headers/header-ncl @@ -0,0 +1,7 @@ +; Copyright (c) 2017, Los Alamos National Security, LLC (LANS) +; and the University Corporation for Atmospheric Research (UCAR). +; +; Unless noted otherwise source code is licensed under the BSD license. +; Additional copyright and license information can be found in the LICENSE file +; distributed with this code, or at http://mpas-dev.github.com/license.html +; \ No newline at end of file diff --git a/licenses/_headers/header-ncl-full b/licenses/_headers/header-ncl-full new file mode 100755 index 000000000..1a923d9db --- /dev/null +++ b/licenses/_headers/header-ncl-full @@ -0,0 +1,39 @@ +; Copyright (c) 2017, Los Alamos National Security, LLC (LANS) (Ocean: LA-CC-13-047; +; Land Ice: LA-CC-13-117) and the University Corporation for Atmospheric Research (UCAR). +; +; All rights reserved. +; +; LANS is the operator of the Los Alamos National Laboratory under Contract No. +; DE-AC52-06NA25396 with the U.S. Department of Energy. UCAR manages the National +; Center for Atmospheric Research under Cooperative Agreement ATM-0753581 with the +; National Science Foundation. The U.S. Government has rights to use, reproduce, +; and distribute this software. NO WARRANTY, EXPRESS OR IMPLIED IS OFFERED BY +; LANS, UCAR OR THE GOVERNMENT AND NONE OF THEM ASSUME ANY LIABILITY FOR THE USE +; OF THIS SOFTWARE. If software is modified to produce derivative works, such +; modified software should be clearly marked, so as not to confuse it with the +; version available from LANS and UCAR. +; +; Additionally, redistribution and use in source and binary forms, with or without +; modification, are permitted provided that the following conditions are met: +; +; 1) Redistributions of source code must retain the above copyright notice, this +; list of conditions and the following disclaimer. +; +; 2) Redistributions in binary form must reproduce the above copyright notice, +; this list of conditions and the following disclaimer in the documentation and/or +; other materials provided with the distribution. +; +; 3) None of the names of LANS, UCAR or the names of its contributors, if any, may +; be used to endorse or promote products derived from this software without +; specific prior written permission. +; +; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +; ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +; DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +; ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +; ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/licenses/_headers/header-py b/licenses/_headers/header-py new file mode 100755 index 000000000..49cdbd5a3 --- /dev/null +++ b/licenses/_headers/header-py @@ -0,0 +1,7 @@ +# Copyright (c) 2017, Los Alamos National Security, LLC (LANS) +# and the University Corporation for Atmospheric Research (UCAR). +# +# Unless noted otherwise source code is licensed under the BSD license. +# Additional copyright and license information can be found in the LICENSE file +# distributed with this code, or at http://mpas-dev.github.com/license.html +# diff --git a/licenses/_headers/header-py-full b/licenses/_headers/header-py-full new file mode 100755 index 000000000..c4f3f2f54 --- /dev/null +++ b/licenses/_headers/header-py-full @@ -0,0 +1,39 @@ +# Copyright (c) 2017, Los Alamos National Security, LLC (LANS) (Ocean: LA-CC-13-047; +# Land Ice: LA-CC-13-117) and the University Corporation for Atmospheric Research (UCAR). +# +# All rights reserved. +# +# LANS is the operator of the Los Alamos National Laboratory under Contract No. +# DE-AC52-06NA25396 with the U.S. Department of Energy. UCAR manages the National +# Center for Atmospheric Research under Cooperative Agreement ATM-0753581 with the +# National Science Foundation. The U.S. Government has rights to use, reproduce, +# and distribute this software. NO WARRANTY, EXPRESS OR IMPLIED IS OFFERED BY +# LANS, UCAR OR THE GOVERNMENT AND NONE OF THEM ASSUME ANY LIABILITY FOR THE USE +# OF THIS SOFTWARE. If software is modified to produce derivative works, such +# modified software should be clearly marked, so as not to confuse it with the +# version available from LANS and UCAR. +# +# Additionally, redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1) Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# 2) Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation and/or +# other materials provided with the distribution. +# +# 3) None of the names of LANS, UCAR or the names of its contributors, if any, may +# be used to endorse or promote products derived from this software without +# specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/licenses/_headers/license-bump-copyright.sh b/licenses/_headers/license-bump-copyright.sh new file mode 100755 index 000000000..e99eced52 --- /dev/null +++ b/licenses/_headers/license-bump-copyright.sh @@ -0,0 +1,66 @@ +#!/usr/bin/env bash +# +# Copyright (c) 2017, UT-BATTELLE, LLC +# All rights reserved. +# +# This software is released under the BSD license detailed +# in the file licenses/A-PRIME_LICENSE +# +# Copyright (c) 2017, Los Alamos National Security, LLC (LANS) +# and the University Corporation for Atmospheric Research (UCAR). +# +# Unless noted otherwise source code is licensed under the BSD license. +# Additional copyright and license information can be found in the LICENSE file +# distributed with this code, or at http://mpas-dev.github.com/license.html +# +# Get the source dir and ignore variables +source license-setup.sh + +OLD="Copyright (c) 2015,2016, UT" +NEW="Copyright (c) 2017, UT" + +ALWAYS_IGNORE=(-not -path "*.git*" -not -path "*docs/*") +FILE_IGNORE=(-not -iname "*.md" -not -iname "*.json" -not -iname "*.txt" \ + -not -iname "*.png" -not -iname "*.jpg" -not -iname "*.svg" ) + +echo "--------------------------------------------------------------------------------" +echo " THESE FILES HAVE AN OUTDATED LICENSE HEADER:" +echo "--------------------------------------------------------------------------------" +find $SOURCE_DIR -type f "${ALWAYS_IGNORE[@]}" \ + "${FILE_IGNORE[@]}" \ + | xargs grep -l "$OLD" \ + | sort + +find ${SOURCE_DIR}/docs -type f \ + -not -path "*_build*" \ + -not -path "*source*" \ + "${FILE_IGNORE[@]}" \ + | xargs grep -l "$OLD" \ + | sort + + +echo "--------------------------------------------------------------------------------" +echo " UPDATING THE LICENSE HEADERS:" +echo "--------------------------------------------------------------------------------" +find $SOURCE_DIR -type f "${ALWAYS_IGNORE[@]}" \ + "${FILE_IGNORE[@]}" \ + | xargs grep -l "$OLD" \ + | sort \ + | while read SRC +do + echo "Bumping $SRC" + sed -i "s/$OLD/$NEW/g" $SRC +done + + +find ${SOURCE_DIR}/docs -type f \ + -not -path "*_build*" \ + -not -path "*source*" \ + "${FILE_IGNORE[@]}" \ + | xargs grep -l "$OLD" \ + | sort \ + | while read SRC +do + echo "Bumping $SRC" + sed -i "s/$OLD/$NEW/g" $SRC +done diff --git a/licenses/_headers/license-find-missing.sh b/licenses/_headers/license-find-missing.sh new file mode 100755 index 000000000..d80f0a140 --- /dev/null +++ b/licenses/_headers/license-find-missing.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env bash +# +# Copyright (c) 2017, UT-BATTELLE, LLC +# All rights reserved. +# +# This software is released under the BSD license detailed +# in the file licenses/A-PRIME_LICENSE +# +# Get the source dir and ignore variables +source license-setup.sh + +echo "--------------------------------------------------------------------------------" +echo " THESE FILES ARE MISSING A CURRENT LICENSE HEADER:" +echo "--------------------------------------------------------------------------------" +find $SOURCE_DIR -type f "${ALWAYS_IGNORE[@]}" \ + "${FILE_IGNORE[@]}" \ + "${PYTHON_IGNORE[@]}" \ + "${CSS_IGNORE[@]}" \ + | xargs grep -L "$CURRENT" \ + | sort + diff --git a/licenses/_headers/license-prepend-missing.sh b/licenses/_headers/license-prepend-missing.sh new file mode 100755 index 000000000..361929298 --- /dev/null +++ b/licenses/_headers/license-prepend-missing.sh @@ -0,0 +1,111 @@ +#!/usr/bin/env bash +# +# Copyright (c) 2017, UT-BATTELLE, LLC +# All rights reserved. +# +# This software is released under the BSD license detailed +# in the file licenses/A-PRIME_LICENSE +# +# Copyright (c) 2017, Los Alamos National Security, LLC (LANS) +# and the University Corporation for Atmospheric Research (UCAR). +# +# Unless noted otherwise source code is licensed under the BSD license. +# Additional copyright and license information can be found in the LICENSE file +# distributed with this code, or at http://mpas-dev.github.com/license.html +# +# Get the source dir and ignore variables +source license-setup.sh + +echo "--------------------------------------------------------------------------------" +echo " PREPENDING A LICENSE HEADER ONTO THESE FILES:" +echo "--------------------------------------------------------------------------------" +find $SOURCE_DIR -type f "${ALWAYS_IGNORE[@]}" \ + "${FILE_IGNORE[@]}" \ + "${PYTHON_IGNORE[@]}" \ + "${CSS_IGNORE[@]}" \ + | xargs grep -L "$CURRENT" \ + | sort + +echo "--------------------------------------------------------------------------------" +echo " BEGIN PREPENDING:" +echo "--------------------------------------------------------------------------------" +############################################################ +# Prepend license header to python files without a shebang. +# Will ignore files with a current license header. +############################################################ +GET=( -iname "*.py" ) + +find $SOURCE_DIR -type f \( "${GET[@]}" \) "${ALWAYS_IGNORE[@]}" "${PYTHON_IGNORE[@]}" \ + | xargs grep -L "#!" \ + | xargs grep -L "$CURRENT" \ + | while read SRC +do + BN=`basename ${SRC}` + echo HEADING ${SRC} + cp header-py /tmp/licHead + cat ${SRC} >> /tmp/licHead + chmod --reference=${SRC} /tmp/licHead + mv /tmp/licHead ${SRC} +done + +####################################################################### +# Prepend license header to python, bash, and sh files with a shebang. +# Will ignore files with a current license header. +####################################################################### +GET=( -iname "*.py" -or -iname "*.sh" -or -iname "*.bash" -or -iname "*.csh" -or -iname "*.pbs") + +find $SOURCE_DIR -type f \( "${GET[@]}" \) "${ALWAYS_IGNORE[@]}" "${PYTHON_IGNORE[@]}" \ + | xargs grep -l --max-count=1 "#!" \ + | xargs grep -L "$CURRENT" \ + | while read SRC +do + BN=`basename ${SRC}` + echo HEADING ${SRC} + cat ${SRC} | head -1 > /tmp/licHead + cat header-py >> /tmp/licHead + cat ${SRC} | tail -n +2 >> /tmp/licHead + chmod --reference=${SRC} /tmp/licHead + mv /tmp/licHead ${SRC} +done + + +#################################################### +# Prepend license header to html files. +# Will ignore files with a current license header. +#################################################### +GET=( -iname "*.html") + +find $SOURCE_DIR -type f \( "${GET[@]}" \) "${ALWAYS_IGNORE[@]}" \ + | xargs grep -L "$CURRENT" \ + | while read SRC +do + BN=`basename ${SRC}` + echo HEADING ${SRC} + cp header-html /tmp/licHead + cat ${SRC} >> /tmp/licHead + chmod --reference=${SRC} /tmp/licHead + mv /tmp/licHead ${SRC} +done + +#################################################### +# Prepend license header to css and js files. +# Will ignore files with a current license header. +#################################################### +GET=( -iname "*.css" -or -iname "*.js" ) + +find $SOURCE_DIR -type f \( "${GET[@]}" \) "${ALWAYS_IGNORE[@]}" "${CSS_IGNORE[@]}" \ + | xargs grep -L "$CURRENT" \ + | while read SRC +do + BN=`basename ${SRC}` + echo HEADING ${SRC} + cp header-css /tmp/licHead + cat ${SRC} >> /tmp/licHead + chmod --reference=${SRC} /tmp/licHead + mv /tmp/licHead ${SRC} +done + +echo "--------------------------------------------------------------------------------" +echo " DONE PREPENDING!" +echo "--------------------------------------------------------------------------------" + diff --git a/licenses/_headers/license-setup.sh b/licenses/_headers/license-setup.sh new file mode 100755 index 000000000..a2063e2d0 --- /dev/null +++ b/licenses/_headers/license-setup.sh @@ -0,0 +1,30 @@ +#!/usr/bin/env bash +# +# Copyright (c) 2017, UT-BATTELLE, LLC +# All rights reserved. +# +# This software is released under the BSD license detailed +# in the file licenses/A-PRIME_LICENSE +# +# Copyright (c) 2017, Los Alamos National Security, LLC (LANS) +# and the University Corporation for Atmospheric Research (UCAR). +# +# Unless noted otherwise source code is licensed under the BSD license. +# Additional copyright and license information can be found in the LICENSE file +# distributed with this code, or at http://mpas-dev.github.com/license.html + +SOURCE_DIR="../.." + +CURRENT="Copyright (c)" + +ALWAYS_IGNORE=(-not -path "*.git*" -not -path "*docs/*" -not -path "build/*" \ + -not -path "dist/*" -not -path "*.egg-info/*" \ + -not -path "licenses/*" ) + +FILE_IGNORE=(-not -iname "*.md" -not -iname "*.json" -not -iname "*.txt" \ + -not -iname "*.png" -not -iname "*.jpg" -not -iname "*.svg" \ + -not -iname "config.*" -not -iname "*.nc"\ + -not -iname "*.pyc" \ + -not -iname "*.sl" -not -iname "*.ps1" -not -iname "*.yml" ) + +PYTHON_IGNORE=(-not -iname "__init__.py") From b506b8c23ad9ed3a5c1d0abdc2f6be277f28c4cf Mon Sep 17 00:00:00 2001 From: Xylar Asay-Davis Date: Sat, 10 Feb 2018 11:04:16 -0700 Subject: [PATCH 33/71] Add license headers to source files --- conda/recipe/build.sh | 7 +++++++ configs/anvil/job_script.anvil.bash | 7 +++++++ configs/cori/job_script.cori-haswell.bash | 7 +++++++ configs/cori/job_script.cori-knl.bash | 7 +++++++ configs/edison/job_script.edison.bash | 7 +++++++ configs/job_script.default.bash | 7 +++++++ configs/lanl/job_script.lanl.bash | 7 +++++++ configs/olcf/job_script.olcf.bash | 7 +++++++ configs/theta/job_script.theta.bash | 7 +++++++ mpas_analysis/analysis_task_template.py | 7 +++++++ .../configuration/mpas_analysis_config_parser.py | 7 +++++++ mpas_analysis/ocean/climatology_map_antarctic_melt.py | 7 +++++++ mpas_analysis/ocean/climatology_map_mld.py | 7 +++++++ mpas_analysis/ocean/climatology_map_sose.py | 7 +++++++ mpas_analysis/ocean/climatology_map_ssh.py | 7 +++++++ mpas_analysis/ocean/climatology_map_sss.py | 7 +++++++ mpas_analysis/ocean/climatology_map_sst.py | 7 +++++++ mpas_analysis/ocean/compute_anomaly_subtask.py | 7 +++++++ mpas_analysis/ocean/index_nino34.py | 7 +++++++ mpas_analysis/ocean/meridional_heat_transport.py | 7 +++++++ mpas_analysis/ocean/plot_climatology_map_subtask.py | 7 +++++++ .../ocean/plot_depth_integrated_time_series_subtask.py | 7 +++++++ mpas_analysis/ocean/plot_hovmoller_subtask.py | 7 +++++++ mpas_analysis/ocean/remap_depth_slices_subtask.py | 7 +++++++ mpas_analysis/ocean/streamfunction_moc.py | 7 +++++++ mpas_analysis/ocean/time_series_antarctic_melt.py | 7 +++++++ mpas_analysis/ocean/time_series_ohc_anomaly.py | 7 +++++++ mpas_analysis/ocean/time_series_salinity_anomaly.py | 7 +++++++ mpas_analysis/ocean/time_series_sst.py | 7 +++++++ mpas_analysis/ocean/time_series_temperature_anomaly.py | 7 +++++++ mpas_analysis/ocean/utility.py | 7 +++++++ mpas_analysis/sea_ice/climatology_map_sea_ice_conc.py | 7 +++++++ mpas_analysis/sea_ice/climatology_map_sea_ice_thick.py | 7 +++++++ mpas_analysis/sea_ice/plot_climatology_map_subtask.py | 7 +++++++ mpas_analysis/sea_ice/time_series.py | 7 +++++++ mpas_analysis/shared/analysis_task.py | 7 +++++++ mpas_analysis/shared/climatology/climatology.py | 7 +++++++ .../shared/climatology/comparison_descriptors.py | 7 +++++++ .../shared/climatology/mpas_climatology_task.py | 7 +++++++ .../climatology/remap_mpas_climatology_subtask.py | 7 +++++++ .../climatology/remap_observed_climatology_subtask.py | 7 +++++++ mpas_analysis/shared/constants/constants.py | 7 +++++++ mpas_analysis/shared/containers.py | 7 +++++++ .../shared/generalized_reader/generalized_reader.py | 7 +++++++ mpas_analysis/shared/grid/grid.py | 7 +++++++ mpas_analysis/shared/html/image_xml.py | 7 +++++++ mpas_analysis/shared/html/pages.py | 7 +++++++ .../shared/html/templates/component_gallery.html | 10 ++++++++++ .../shared/html/templates/component_group.html | 10 ++++++++++ .../shared/html/templates/component_image.html | 10 ++++++++++ .../shared/html/templates/component_quicklink.html | 10 ++++++++++ .../shared/html/templates/component_subtitle.html | 10 ++++++++++ mpas_analysis/shared/html/templates/index.js | 10 ++++++++++ .../shared/html/templates/main_component.html | 10 ++++++++++ mpas_analysis/shared/html/templates/main_page.html | 10 ++++++++++ mpas_analysis/shared/html/templates/style.css | 10 ++++++++++ mpas_analysis/shared/interpolation/remapper.py | 7 +++++++ mpas_analysis/shared/io/mpas_reader.py | 7 +++++++ mpas_analysis/shared/io/namelist_streams_interface.py | 7 +++++++ mpas_analysis/shared/io/utility.py | 7 +++++++ mpas_analysis/shared/io/write_netcdf.py | 7 +++++++ mpas_analysis/shared/mpas_xarray/mpas_xarray.py | 7 +++++++ mpas_analysis/shared/plot/plotting.py | 7 +++++++ mpas_analysis/shared/time_series/anomaly.py | 7 +++++++ mpas_analysis/shared/time_series/moving_average.py | 7 +++++++ .../shared/time_series/mpas_time_series_task.py | 7 +++++++ mpas_analysis/shared/time_series/time_series.py | 7 +++++++ mpas_analysis/shared/timekeeping/MpasRelativeDelta.py | 7 +++++++ mpas_analysis/shared/timekeeping/utility.py | 7 +++++++ mpas_analysis/test/test_analysis_task.py | 7 +++++++ mpas_analysis/test/test_climatology.py | 7 +++++++ mpas_analysis/test/test_generalized_reader.py | 7 +++++++ mpas_analysis/test/test_interpolate.py | 7 +++++++ mpas_analysis/test/test_io_utility.py | 7 +++++++ mpas_analysis/test/test_mpas_climatology_task.py | 7 +++++++ mpas_analysis/test/test_mpas_config_parser.py | 7 +++++++ mpas_analysis/test/test_mpas_xarray.py | 7 +++++++ mpas_analysis/test/test_namelist_streams_interface.py | 7 +++++++ mpas_analysis/test/test_open_mpas_dataset.py | 7 +++++++ mpas_analysis/test/test_remap_obs_clim_subtask.py | 7 +++++++ .../test/test_remap_obs_clim_subtask/remap_mld_obs.py | 7 +++++++ mpas_analysis/test/test_timekeeping.py | 7 +++++++ preprocess_masks/make_ice_shelf_masks.py | 7 +++++++ preprocess_observations/mds.py | 7 +++++++ preprocess_observations/remap_SOSE_T_S.py | 7 +++++++ preprocess_observations/remap_rignot.py | 7 +++++++ setup.py | 7 +++++++ utility_scripts/make_mpas_to_lat_lon_mapping.py | 7 +++++++ 88 files changed, 643 insertions(+) diff --git a/conda/recipe/build.sh b/conda/recipe/build.sh index 383455d82..2249089f8 100644 --- a/conda/recipe/build.sh +++ b/conda/recipe/build.sh @@ -1,2 +1,9 @@ #!/usr/bin/sh +# Copyright (c) 2017, Los Alamos National Security, LLC (LANS) +# and the University Corporation for Atmospheric Research (UCAR). +# +# Unless noted otherwise source code is licensed under the BSD license. +# Additional copyright and license information can be found in the LICENSE file +# distributed with this code, or at http://mpas-dev.github.com/license.html +# python setup.py install --single-version-externally-managed --record=record.txt diff --git a/configs/anvil/job_script.anvil.bash b/configs/anvil/job_script.anvil.bash index 36f3d2e9a..49d7ff98c 100644 --- a/configs/anvil/job_script.anvil.bash +++ b/configs/anvil/job_script.anvil.bash @@ -1,4 +1,11 @@ #!/bin/bash +# Copyright (c) 2017, Los Alamos National Security, LLC (LANS) +# and the University Corporation for Atmospheric Research (UCAR). +# +# Unless noted otherwise source code is licensed under the BSD license. +# Additional copyright and license information can be found in the LICENSE file +# distributed with this code, or at http://mpas-dev.github.com/license.html +# # comment out if using debug queue #PBS -q acme diff --git a/configs/cori/job_script.cori-haswell.bash b/configs/cori/job_script.cori-haswell.bash index aefa4fb46..8aa6f1cf9 100644 --- a/configs/cori/job_script.cori-haswell.bash +++ b/configs/cori/job_script.cori-haswell.bash @@ -1,4 +1,11 @@ #!/bin/bash -l +# Copyright (c) 2017, Los Alamos National Security, LLC (LANS) +# and the University Corporation for Atmospheric Research (UCAR). +# +# Unless noted otherwise source code is licensed under the BSD license. +# Additional copyright and license information can be found in the LICENSE file +# distributed with this code, or at http://mpas-dev.github.com/license.html +# # comment out if using debug queue #SBATCH --partition=regular diff --git a/configs/cori/job_script.cori-knl.bash b/configs/cori/job_script.cori-knl.bash index b3936933b..2fe656738 100644 --- a/configs/cori/job_script.cori-knl.bash +++ b/configs/cori/job_script.cori-knl.bash @@ -1,4 +1,11 @@ #!/bin/bash -l +# Copyright (c) 2017, Los Alamos National Security, LLC (LANS) +# and the University Corporation for Atmospheric Research (UCAR). +# +# Unless noted otherwise source code is licensed under the BSD license. +# Additional copyright and license information can be found in the LICENSE file +# distributed with this code, or at http://mpas-dev.github.com/license.html +# # comment out if using debug queue #SBATCH --partition=regular diff --git a/configs/edison/job_script.edison.bash b/configs/edison/job_script.edison.bash index f1098dc6e..922df234d 100644 --- a/configs/edison/job_script.edison.bash +++ b/configs/edison/job_script.edison.bash @@ -1,4 +1,11 @@ #!/bin/bash -l +# Copyright (c) 2017, Los Alamos National Security, LLC (LANS) +# and the University Corporation for Atmospheric Research (UCAR). +# +# Unless noted otherwise source code is licensed under the BSD license. +# Additional copyright and license information can be found in the LICENSE file +# distributed with this code, or at http://mpas-dev.github.com/license.html +# # comment out if using debug queue #SBATCH --partition=regular diff --git a/configs/job_script.default.bash b/configs/job_script.default.bash index 565d423ab..f96ea54e3 100755 --- a/configs/job_script.default.bash +++ b/configs/job_script.default.bash @@ -1,4 +1,11 @@ #!/bin/bash +# Copyright (c) 2017, Los Alamos National Security, LLC (LANS) +# and the University Corporation for Atmospheric Research (UCAR). +# +# Unless noted otherwise source code is licensed under the BSD license. +# Additional copyright and license information can be found in the LICENSE file +# distributed with this code, or at http://mpas-dev.github.com/license.html +# # MPAS/ACME job to be analyzed, including paths to simulation data and # observations. Change this name and path as needed diff --git a/configs/lanl/job_script.lanl.bash b/configs/lanl/job_script.lanl.bash index f42ffb377..19978ba92 100644 --- a/configs/lanl/job_script.lanl.bash +++ b/configs/lanl/job_script.lanl.bash @@ -1,4 +1,11 @@ #!/bin/bash +# Copyright (c) 2017, Los Alamos National Security, LLC (LANS) +# and the University Corporation for Atmospheric Research (UCAR). +# +# Unless noted otherwise source code is licensed under the BSD license. +# Additional copyright and license information can be found in the LICENSE file +# distributed with this code, or at http://mpas-dev.github.com/license.html +# # change number of nodes to change the number of parallel tasks # (anything between 1 and the total number of tasks to run) diff --git a/configs/olcf/job_script.olcf.bash b/configs/olcf/job_script.olcf.bash index 42114f0e7..8d6c55f36 100644 --- a/configs/olcf/job_script.olcf.bash +++ b/configs/olcf/job_script.olcf.bash @@ -1,4 +1,11 @@ #!/bin/bash +# Copyright (c) 2017, Los Alamos National Security, LLC (LANS) +# and the University Corporation for Atmospheric Research (UCAR). +# +# Unless noted otherwise source code is licensed under the BSD license. +# Additional copyright and license information can be found in the LICENSE file +# distributed with this code, or at http://mpas-dev.github.com/license.html +# # comment out if using debug queue #PBS -q batch diff --git a/configs/theta/job_script.theta.bash b/configs/theta/job_script.theta.bash index 0b681a7e9..3797f166e 100755 --- a/configs/theta/job_script.theta.bash +++ b/configs/theta/job_script.theta.bash @@ -1,4 +1,11 @@ #!/bin/bash +# Copyright (c) 2017, Los Alamos National Security, LLC (LANS) +# and the University Corporation for Atmospheric Research (UCAR). +# +# Unless noted otherwise source code is licensed under the BSD license. +# Additional copyright and license information can be found in the LICENSE file +# distributed with this code, or at http://mpas-dev.github.com/license.html +# #COBALT -t 1:00:00 #COBALT -n 1 #COBALT -A OceanClimate diff --git a/mpas_analysis/analysis_task_template.py b/mpas_analysis/analysis_task_template.py index 0c53f46e7..8b1a93bbb 100644 --- a/mpas_analysis/analysis_task_template.py +++ b/mpas_analysis/analysis_task_template.py @@ -1,3 +1,10 @@ +# Copyright (c) 2017, Los Alamos National Security, LLC (LANS) +# and the University Corporation for Atmospheric Research (UCAR). +# +# Unless noted otherwise source code is licensed under the BSD license. +# Additional copyright and license information can be found in the LICENSE file +# distributed with this code, or at http://mpas-dev.github.com/license.html +# ''' This is an example analysis task to be used as a template for new tasks. It should be copied into one of the component folders (`ocean`, `sea_ice`, diff --git a/mpas_analysis/configuration/mpas_analysis_config_parser.py b/mpas_analysis/configuration/mpas_analysis_config_parser.py index 06f2472cf..0440f4768 100644 --- a/mpas_analysis/configuration/mpas_analysis_config_parser.py +++ b/mpas_analysis/configuration/mpas_analysis_config_parser.py @@ -1,3 +1,10 @@ +# Copyright (c) 2017, Los Alamos National Security, LLC (LANS) +# and the University Corporation for Atmospheric Research (UCAR). +# +# Unless noted otherwise source code is licensed under the BSD license. +# Additional copyright and license information can be found in the LICENSE file +# distributed with this code, or at http://mpas-dev.github.com/license.html +# """ A configuratin parser class for MPAS analysis. MpasAnalysisConfigParser adds the capabilities to get an option including a default value diff --git a/mpas_analysis/ocean/climatology_map_antarctic_melt.py b/mpas_analysis/ocean/climatology_map_antarctic_melt.py index 07002cc73..5d24b6f86 100644 --- a/mpas_analysis/ocean/climatology_map_antarctic_melt.py +++ b/mpas_analysis/ocean/climatology_map_antarctic_melt.py @@ -1,3 +1,10 @@ +# Copyright (c) 2017, Los Alamos National Security, LLC (LANS) +# and the University Corporation for Atmospheric Research (UCAR). +# +# Unless noted otherwise source code is licensed under the BSD license. +# Additional copyright and license information can be found in the LICENSE file +# distributed with this code, or at http://mpas-dev.github.com/license.html +# from __future__ import absolute_import, division, print_function, \ unicode_literals diff --git a/mpas_analysis/ocean/climatology_map_mld.py b/mpas_analysis/ocean/climatology_map_mld.py index 6631d2c8e..e8f61b48b 100644 --- a/mpas_analysis/ocean/climatology_map_mld.py +++ b/mpas_analysis/ocean/climatology_map_mld.py @@ -1,3 +1,10 @@ +# Copyright (c) 2017, Los Alamos National Security, LLC (LANS) +# and the University Corporation for Atmospheric Research (UCAR). +# +# Unless noted otherwise source code is licensed under the BSD license. +# Additional copyright and license information can be found in the LICENSE file +# distributed with this code, or at http://mpas-dev.github.com/license.html +# from __future__ import absolute_import, division, print_function, \ unicode_literals diff --git a/mpas_analysis/ocean/climatology_map_sose.py b/mpas_analysis/ocean/climatology_map_sose.py index ef23524ab..9ac4037d8 100644 --- a/mpas_analysis/ocean/climatology_map_sose.py +++ b/mpas_analysis/ocean/climatology_map_sose.py @@ -1,3 +1,10 @@ +# Copyright (c) 2017, Los Alamos National Security, LLC (LANS) +# and the University Corporation for Atmospheric Research (UCAR). +# +# Unless noted otherwise source code is licensed under the BSD license. +# Additional copyright and license information can be found in the LICENSE file +# distributed with this code, or at http://mpas-dev.github.com/license.html +# ''' Analysis tasks for comparing Antarctic climatology maps against observations and reanalysis data. diff --git a/mpas_analysis/ocean/climatology_map_ssh.py b/mpas_analysis/ocean/climatology_map_ssh.py index bab7483f6..5838ba283 100644 --- a/mpas_analysis/ocean/climatology_map_ssh.py +++ b/mpas_analysis/ocean/climatology_map_ssh.py @@ -1,3 +1,10 @@ +# Copyright (c) 2017, Los Alamos National Security, LLC (LANS) +# and the University Corporation for Atmospheric Research (UCAR). +# +# Unless noted otherwise source code is licensed under the BSD license. +# Additional copyright and license information can be found in the LICENSE file +# distributed with this code, or at http://mpas-dev.github.com/license.html +# from __future__ import absolute_import, division, print_function, \ unicode_literals diff --git a/mpas_analysis/ocean/climatology_map_sss.py b/mpas_analysis/ocean/climatology_map_sss.py index 7e8f27a55..069a34359 100644 --- a/mpas_analysis/ocean/climatology_map_sss.py +++ b/mpas_analysis/ocean/climatology_map_sss.py @@ -1,3 +1,10 @@ +# Copyright (c) 2017, Los Alamos National Security, LLC (LANS) +# and the University Corporation for Atmospheric Research (UCAR). +# +# Unless noted otherwise source code is licensed under the BSD license. +# Additional copyright and license information can be found in the LICENSE file +# distributed with this code, or at http://mpas-dev.github.com/license.html +# from __future__ import absolute_import, division, print_function, \ unicode_literals diff --git a/mpas_analysis/ocean/climatology_map_sst.py b/mpas_analysis/ocean/climatology_map_sst.py index b7c99a8f5..35bcb6246 100644 --- a/mpas_analysis/ocean/climatology_map_sst.py +++ b/mpas_analysis/ocean/climatology_map_sst.py @@ -1,3 +1,10 @@ +# Copyright (c) 2017, Los Alamos National Security, LLC (LANS) +# and the University Corporation for Atmospheric Research (UCAR). +# +# Unless noted otherwise source code is licensed under the BSD license. +# Additional copyright and license information can be found in the LICENSE file +# distributed with this code, or at http://mpas-dev.github.com/license.html +# from __future__ import absolute_import, division, print_function, \ unicode_literals diff --git a/mpas_analysis/ocean/compute_anomaly_subtask.py b/mpas_analysis/ocean/compute_anomaly_subtask.py index 49773a538..7b66bd125 100644 --- a/mpas_analysis/ocean/compute_anomaly_subtask.py +++ b/mpas_analysis/ocean/compute_anomaly_subtask.py @@ -1,3 +1,10 @@ +# Copyright (c) 2017, Los Alamos National Security, LLC (LANS) +# and the University Corporation for Atmospheric Research (UCAR). +# +# Unless noted otherwise source code is licensed under the BSD license. +# Additional copyright and license information can be found in the LICENSE file +# distributed with this code, or at http://mpas-dev.github.com/license.html +# # -*- coding: utf-8 -*- from __future__ import absolute_import, division, print_function, \ diff --git a/mpas_analysis/ocean/index_nino34.py b/mpas_analysis/ocean/index_nino34.py index 105342af2..add345e69 100644 --- a/mpas_analysis/ocean/index_nino34.py +++ b/mpas_analysis/ocean/index_nino34.py @@ -1,3 +1,10 @@ +# Copyright (c) 2017, Los Alamos National Security, LLC (LANS) +# and the University Corporation for Atmospheric Research (UCAR). +# +# Unless noted otherwise source code is licensed under the BSD license. +# Additional copyright and license information can be found in the LICENSE file +# distributed with this code, or at http://mpas-dev.github.com/license.html +# # -*- coding: utf-8 -*- from __future__ import absolute_import, division, print_function, \ diff --git a/mpas_analysis/ocean/meridional_heat_transport.py b/mpas_analysis/ocean/meridional_heat_transport.py index 218203f41..161f599fa 100644 --- a/mpas_analysis/ocean/meridional_heat_transport.py +++ b/mpas_analysis/ocean/meridional_heat_transport.py @@ -1,3 +1,10 @@ +# Copyright (c) 2017, Los Alamos National Security, LLC (LANS) +# and the University Corporation for Atmospheric Research (UCAR). +# +# Unless noted otherwise source code is licensed under the BSD license. +# Additional copyright and license information can be found in the LICENSE file +# distributed with this code, or at http://mpas-dev.github.com/license.html +# from __future__ import absolute_import, division, print_function, \ unicode_literals diff --git a/mpas_analysis/ocean/plot_climatology_map_subtask.py b/mpas_analysis/ocean/plot_climatology_map_subtask.py index 3d68a766b..5ec9d73b6 100644 --- a/mpas_analysis/ocean/plot_climatology_map_subtask.py +++ b/mpas_analysis/ocean/plot_climatology_map_subtask.py @@ -1,3 +1,10 @@ +# Copyright (c) 2017, Los Alamos National Security, LLC (LANS) +# and the University Corporation for Atmospheric Research (UCAR). +# +# Unless noted otherwise source code is licensed under the BSD license. +# Additional copyright and license information can be found in the LICENSE file +# distributed with this code, or at http://mpas-dev.github.com/license.html +# """ An analysis subtasks for plotting comparison of 2D model fields against observations. diff --git a/mpas_analysis/ocean/plot_depth_integrated_time_series_subtask.py b/mpas_analysis/ocean/plot_depth_integrated_time_series_subtask.py index ad98cd56c..e6b49d942 100644 --- a/mpas_analysis/ocean/plot_depth_integrated_time_series_subtask.py +++ b/mpas_analysis/ocean/plot_depth_integrated_time_series_subtask.py @@ -1,3 +1,10 @@ +# Copyright (c) 2017, Los Alamos National Security, LLC (LANS) +# and the University Corporation for Atmospheric Research (UCAR). +# +# Unless noted otherwise source code is licensed under the BSD license. +# Additional copyright and license information can be found in the LICENSE file +# distributed with this code, or at http://mpas-dev.github.com/license.html +# # -*- coding: utf-8 -*- from __future__ import absolute_import, division, print_function, \ diff --git a/mpas_analysis/ocean/plot_hovmoller_subtask.py b/mpas_analysis/ocean/plot_hovmoller_subtask.py index 8543325e8..c48018690 100644 --- a/mpas_analysis/ocean/plot_hovmoller_subtask.py +++ b/mpas_analysis/ocean/plot_hovmoller_subtask.py @@ -1,3 +1,10 @@ +# Copyright (c) 2017, Los Alamos National Security, LLC (LANS) +# and the University Corporation for Atmospheric Research (UCAR). +# +# Unless noted otherwise source code is licensed under the BSD license. +# Additional copyright and license information can be found in the LICENSE file +# distributed with this code, or at http://mpas-dev.github.com/license.html +# # -*- coding: utf-8 -*- from __future__ import absolute_import, division, print_function, \ diff --git a/mpas_analysis/ocean/remap_depth_slices_subtask.py b/mpas_analysis/ocean/remap_depth_slices_subtask.py index b2102ae59..1debd1552 100644 --- a/mpas_analysis/ocean/remap_depth_slices_subtask.py +++ b/mpas_analysis/ocean/remap_depth_slices_subtask.py @@ -1,3 +1,10 @@ +# Copyright (c) 2017, Los Alamos National Security, LLC (LANS) +# and the University Corporation for Atmospheric Research (UCAR). +# +# Unless noted otherwise source code is licensed under the BSD license. +# Additional copyright and license information can be found in the LICENSE file +# distributed with this code, or at http://mpas-dev.github.com/license.html +# from __future__ import absolute_import, division, print_function, \ unicode_literals diff --git a/mpas_analysis/ocean/streamfunction_moc.py b/mpas_analysis/ocean/streamfunction_moc.py index 59fc2d84f..77b7f50dc 100644 --- a/mpas_analysis/ocean/streamfunction_moc.py +++ b/mpas_analysis/ocean/streamfunction_moc.py @@ -1,3 +1,10 @@ +# Copyright (c) 2017, Los Alamos National Security, LLC (LANS) +# and the University Corporation for Atmospheric Research (UCAR). +# +# Unless noted otherwise source code is licensed under the BSD license. +# Additional copyright and license information can be found in the LICENSE file +# distributed with this code, or at http://mpas-dev.github.com/license.html +# # -*- coding: utf-8 -*- from __future__ import absolute_import, division, print_function, \ diff --git a/mpas_analysis/ocean/time_series_antarctic_melt.py b/mpas_analysis/ocean/time_series_antarctic_melt.py index 743da8af3..fb0396401 100644 --- a/mpas_analysis/ocean/time_series_antarctic_melt.py +++ b/mpas_analysis/ocean/time_series_antarctic_melt.py @@ -1,3 +1,10 @@ +# Copyright (c) 2017, Los Alamos National Security, LLC (LANS) +# and the University Corporation for Atmospheric Research (UCAR). +# +# Unless noted otherwise source code is licensed under the BSD license. +# Additional copyright and license information can be found in the LICENSE file +# distributed with this code, or at http://mpas-dev.github.com/license.html +# from __future__ import absolute_import, division, print_function, \ unicode_literals diff --git a/mpas_analysis/ocean/time_series_ohc_anomaly.py b/mpas_analysis/ocean/time_series_ohc_anomaly.py index 00d6e3594..bda379661 100644 --- a/mpas_analysis/ocean/time_series_ohc_anomaly.py +++ b/mpas_analysis/ocean/time_series_ohc_anomaly.py @@ -1,3 +1,10 @@ +# Copyright (c) 2017, Los Alamos National Security, LLC (LANS) +# and the University Corporation for Atmospheric Research (UCAR). +# +# Unless noted otherwise source code is licensed under the BSD license. +# Additional copyright and license information can be found in the LICENSE file +# distributed with this code, or at http://mpas-dev.github.com/license.html +# # -*- coding: utf-8 -*- from __future__ import absolute_import, division, print_function, \ diff --git a/mpas_analysis/ocean/time_series_salinity_anomaly.py b/mpas_analysis/ocean/time_series_salinity_anomaly.py index 3f29492b3..f566415af 100644 --- a/mpas_analysis/ocean/time_series_salinity_anomaly.py +++ b/mpas_analysis/ocean/time_series_salinity_anomaly.py @@ -1,3 +1,10 @@ +# Copyright (c) 2017, Los Alamos National Security, LLC (LANS) +# and the University Corporation for Atmospheric Research (UCAR). +# +# Unless noted otherwise source code is licensed under the BSD license. +# Additional copyright and license information can be found in the LICENSE file +# distributed with this code, or at http://mpas-dev.github.com/license.html +# # -*- coding: utf-8 -*- from __future__ import absolute_import, division, print_function, \ diff --git a/mpas_analysis/ocean/time_series_sst.py b/mpas_analysis/ocean/time_series_sst.py index 9b889288d..c49ead643 100644 --- a/mpas_analysis/ocean/time_series_sst.py +++ b/mpas_analysis/ocean/time_series_sst.py @@ -1,3 +1,10 @@ +# Copyright (c) 2017, Los Alamos National Security, LLC (LANS) +# and the University Corporation for Atmospheric Research (UCAR). +# +# Unless noted otherwise source code is licensed under the BSD license. +# Additional copyright and license information can be found in the LICENSE file +# distributed with this code, or at http://mpas-dev.github.com/license.html +# from __future__ import absolute_import, division, print_function, \ unicode_literals diff --git a/mpas_analysis/ocean/time_series_temperature_anomaly.py b/mpas_analysis/ocean/time_series_temperature_anomaly.py index 9e61b2156..ab9c251f2 100644 --- a/mpas_analysis/ocean/time_series_temperature_anomaly.py +++ b/mpas_analysis/ocean/time_series_temperature_anomaly.py @@ -1,3 +1,10 @@ +# Copyright (c) 2017, Los Alamos National Security, LLC (LANS) +# and the University Corporation for Atmospheric Research (UCAR). +# +# Unless noted otherwise source code is licensed under the BSD license. +# Additional copyright and license information can be found in the LICENSE file +# distributed with this code, or at http://mpas-dev.github.com/license.html +# # -*- coding: utf-8 -*- from __future__ import absolute_import, division, print_function, \ diff --git a/mpas_analysis/ocean/utility.py b/mpas_analysis/ocean/utility.py index 8600977ef..f58fc1e4a 100644 --- a/mpas_analysis/ocean/utility.py +++ b/mpas_analysis/ocean/utility.py @@ -1,3 +1,10 @@ +# Copyright (c) 2017, Los Alamos National Security, LLC (LANS) +# and the University Corporation for Atmospheric Research (UCAR). +# +# Unless noted otherwise source code is licensed under the BSD license. +# Additional copyright and license information can be found in the LICENSE file +# distributed with this code, or at http://mpas-dev.github.com/license.html +# """ A utility for computing common ocean fields (e.g. zMid) from datasets diff --git a/mpas_analysis/sea_ice/climatology_map_sea_ice_conc.py b/mpas_analysis/sea_ice/climatology_map_sea_ice_conc.py index b1909dec0..8d48169ef 100644 --- a/mpas_analysis/sea_ice/climatology_map_sea_ice_conc.py +++ b/mpas_analysis/sea_ice/climatology_map_sea_ice_conc.py @@ -1,3 +1,10 @@ +# Copyright (c) 2017, Los Alamos National Security, LLC (LANS) +# and the University Corporation for Atmospheric Research (UCAR). +# +# Unless noted otherwise source code is licensed under the BSD license. +# Additional copyright and license information can be found in the LICENSE file +# distributed with this code, or at http://mpas-dev.github.com/license.html +# from __future__ import absolute_import, division, print_function, \ unicode_literals diff --git a/mpas_analysis/sea_ice/climatology_map_sea_ice_thick.py b/mpas_analysis/sea_ice/climatology_map_sea_ice_thick.py index 957b15830..03c343278 100644 --- a/mpas_analysis/sea_ice/climatology_map_sea_ice_thick.py +++ b/mpas_analysis/sea_ice/climatology_map_sea_ice_thick.py @@ -1,3 +1,10 @@ +# Copyright (c) 2017, Los Alamos National Security, LLC (LANS) +# and the University Corporation for Atmospheric Research (UCAR). +# +# Unless noted otherwise source code is licensed under the BSD license. +# Additional copyright and license information can be found in the LICENSE file +# distributed with this code, or at http://mpas-dev.github.com/license.html +# from __future__ import absolute_import, division, print_function, \ unicode_literals diff --git a/mpas_analysis/sea_ice/plot_climatology_map_subtask.py b/mpas_analysis/sea_ice/plot_climatology_map_subtask.py index 5393ee826..4af15d4cc 100644 --- a/mpas_analysis/sea_ice/plot_climatology_map_subtask.py +++ b/mpas_analysis/sea_ice/plot_climatology_map_subtask.py @@ -1,3 +1,10 @@ +# Copyright (c) 2017, Los Alamos National Security, LLC (LANS) +# and the University Corporation for Atmospheric Research (UCAR). +# +# Unless noted otherwise source code is licensed under the BSD license. +# Additional copyright and license information can be found in the LICENSE file +# distributed with this code, or at http://mpas-dev.github.com/license.html +# from __future__ import absolute_import, division, print_function, \ unicode_literals diff --git a/mpas_analysis/sea_ice/time_series.py b/mpas_analysis/sea_ice/time_series.py index 67d34915b..00b77b6fd 100644 --- a/mpas_analysis/sea_ice/time_series.py +++ b/mpas_analysis/sea_ice/time_series.py @@ -1,3 +1,10 @@ +# Copyright (c) 2017, Los Alamos National Security, LLC (LANS) +# and the University Corporation for Atmospheric Research (UCAR). +# +# Unless noted otherwise source code is licensed under the BSD license. +# Additional copyright and license information can be found in the LICENSE file +# distributed with this code, or at http://mpas-dev.github.com/license.html +# from __future__ import absolute_import, division, print_function, \ unicode_literals diff --git a/mpas_analysis/shared/analysis_task.py b/mpas_analysis/shared/analysis_task.py index 2e7b7d70b..6a06fed0a 100644 --- a/mpas_analysis/shared/analysis_task.py +++ b/mpas_analysis/shared/analysis_task.py @@ -1,3 +1,10 @@ +# Copyright (c) 2017, Los Alamos National Security, LLC (LANS) +# and the University Corporation for Atmospheric Research (UCAR). +# +# Unless noted otherwise source code is licensed under the BSD license. +# Additional copyright and license information can be found in the LICENSE file +# distributed with this code, or at http://mpas-dev.github.com/license.html +# ''' Defines the base class for analysis tasks. diff --git a/mpas_analysis/shared/climatology/climatology.py b/mpas_analysis/shared/climatology/climatology.py index c2b411465..52a53433b 100644 --- a/mpas_analysis/shared/climatology/climatology.py +++ b/mpas_analysis/shared/climatology/climatology.py @@ -1,3 +1,10 @@ +# Copyright (c) 2017, Los Alamos National Security, LLC (LANS) +# and the University Corporation for Atmospheric Research (UCAR). +# +# Unless noted otherwise source code is licensed under the BSD license. +# Additional copyright and license information can be found in the LICENSE file +# distributed with this code, or at http://mpas-dev.github.com/license.html +# """ Functions for creating climatologies from monthly time series data diff --git a/mpas_analysis/shared/climatology/comparison_descriptors.py b/mpas_analysis/shared/climatology/comparison_descriptors.py index ed553070f..a417de531 100644 --- a/mpas_analysis/shared/climatology/comparison_descriptors.py +++ b/mpas_analysis/shared/climatology/comparison_descriptors.py @@ -1,3 +1,10 @@ +# Copyright (c) 2017, Los Alamos National Security, LLC (LANS) +# and the University Corporation for Atmospheric Research (UCAR). +# +# Unless noted otherwise source code is licensed under the BSD license. +# Additional copyright and license information can be found in the LICENSE file +# distributed with this code, or at http://mpas-dev.github.com/license.html +# """ Functions for creating climatologies from monthly time series data diff --git a/mpas_analysis/shared/climatology/mpas_climatology_task.py b/mpas_analysis/shared/climatology/mpas_climatology_task.py index e4d4d2e73..041ac12cb 100644 --- a/mpas_analysis/shared/climatology/mpas_climatology_task.py +++ b/mpas_analysis/shared/climatology/mpas_climatology_task.py @@ -1,3 +1,10 @@ +# Copyright (c) 2017, Los Alamos National Security, LLC (LANS) +# and the University Corporation for Atmospheric Research (UCAR). +# +# Unless noted otherwise source code is licensed under the BSD license. +# Additional copyright and license information can be found in the LICENSE file +# distributed with this code, or at http://mpas-dev.github.com/license.html +# from __future__ import absolute_import, division, print_function, \ unicode_literals diff --git a/mpas_analysis/shared/climatology/remap_mpas_climatology_subtask.py b/mpas_analysis/shared/climatology/remap_mpas_climatology_subtask.py index 771e97649..21ba4f828 100644 --- a/mpas_analysis/shared/climatology/remap_mpas_climatology_subtask.py +++ b/mpas_analysis/shared/climatology/remap_mpas_climatology_subtask.py @@ -1,3 +1,10 @@ +# Copyright (c) 2017, Los Alamos National Security, LLC (LANS) +# and the University Corporation for Atmospheric Research (UCAR). +# +# Unless noted otherwise source code is licensed under the BSD license. +# Additional copyright and license information can be found in the LICENSE file +# distributed with this code, or at http://mpas-dev.github.com/license.html +# from __future__ import absolute_import, division, print_function, \ unicode_literals diff --git a/mpas_analysis/shared/climatology/remap_observed_climatology_subtask.py b/mpas_analysis/shared/climatology/remap_observed_climatology_subtask.py index ba39e3cbf..49dd97957 100644 --- a/mpas_analysis/shared/climatology/remap_observed_climatology_subtask.py +++ b/mpas_analysis/shared/climatology/remap_observed_climatology_subtask.py @@ -1,3 +1,10 @@ +# Copyright (c) 2017, Los Alamos National Security, LLC (LANS) +# and the University Corporation for Atmospheric Research (UCAR). +# +# Unless noted otherwise source code is licensed under the BSD license. +# Additional copyright and license information can be found in the LICENSE file +# distributed with this code, or at http://mpas-dev.github.com/license.html +# from __future__ import absolute_import, division, print_function, \ unicode_literals diff --git a/mpas_analysis/shared/constants/constants.py b/mpas_analysis/shared/constants/constants.py index 7231fe7be..584187063 100644 --- a/mpas_analysis/shared/constants/constants.py +++ b/mpas_analysis/shared/constants/constants.py @@ -1,3 +1,10 @@ +# Copyright (c) 2017, Los Alamos National Security, LLC (LANS) +# and the University Corporation for Atmospheric Research (UCAR). +# +# Unless noted otherwise source code is licensed under the BSD license. +# Additional copyright and license information can be found in the LICENSE file +# distributed with this code, or at http://mpas-dev.github.com/license.html +# """ Constants that are common to all analysis tasks diff --git a/mpas_analysis/shared/containers.py b/mpas_analysis/shared/containers.py index 8c2583a85..27e725412 100644 --- a/mpas_analysis/shared/containers.py +++ b/mpas_analysis/shared/containers.py @@ -1,4 +1,11 @@ #!/usr/bin/env python +# Copyright (c) 2017, Los Alamos National Security, LLC (LANS) +# and the University Corporation for Atmospheric Research (UCAR). +# +# Unless noted otherwise source code is licensed under the BSD license. +# Additional copyright and license information can be found in the LICENSE file +# distributed with this code, or at http://mpas-dev.github.com/license.html +# """ Module of custom container data types diff --git a/mpas_analysis/shared/generalized_reader/generalized_reader.py b/mpas_analysis/shared/generalized_reader/generalized_reader.py index 87b357baa..a97cf0ede 100644 --- a/mpas_analysis/shared/generalized_reader/generalized_reader.py +++ b/mpas_analysis/shared/generalized_reader/generalized_reader.py @@ -1,3 +1,10 @@ +# Copyright (c) 2017, Los Alamos National Security, LLC (LANS) +# and the University Corporation for Atmospheric Research (UCAR). +# +# Unless noted otherwise source code is licensed under the BSD license. +# Additional copyright and license information can be found in the LICENSE file +# distributed with this code, or at http://mpas-dev.github.com/license.html +# """ Utility functions for importing MPAS files into xarray. These functions extend the capabilities of mpas_xarray to include mapping variable names from MPAS diff --git a/mpas_analysis/shared/grid/grid.py b/mpas_analysis/shared/grid/grid.py index ba7c4096d..cb33c5ae4 100644 --- a/mpas_analysis/shared/grid/grid.py +++ b/mpas_analysis/shared/grid/grid.py @@ -1,3 +1,10 @@ +# Copyright (c) 2017, Los Alamos National Security, LLC (LANS) +# and the University Corporation for Atmospheric Research (UCAR). +# +# Unless noted otherwise source code is licensed under the BSD license. +# Additional copyright and license information can be found in the LICENSE file +# distributed with this code, or at http://mpas-dev.github.com/license.html +# ''' Classes for describing meshes and grids , including creating SCRIP files, used to create mapping files diff --git a/mpas_analysis/shared/html/image_xml.py b/mpas_analysis/shared/html/image_xml.py index a05a8c2f4..e2c1aa770 100644 --- a/mpas_analysis/shared/html/image_xml.py +++ b/mpas_analysis/shared/html/image_xml.py @@ -1,3 +1,10 @@ +# Copyright (c) 2017, Los Alamos National Security, LLC (LANS) +# and the University Corporation for Atmospheric Research (UCAR). +# +# Unless noted otherwise source code is licensed under the BSD license. +# Additional copyright and license information can be found in the LICENSE file +# distributed with this code, or at http://mpas-dev.github.com/license.html +# from __future__ import absolute_import, division, print_function, \ unicode_literals diff --git a/mpas_analysis/shared/html/pages.py b/mpas_analysis/shared/html/pages.py index 97edc12d5..dd70a38a7 100644 --- a/mpas_analysis/shared/html/pages.py +++ b/mpas_analysis/shared/html/pages.py @@ -1,3 +1,10 @@ +# Copyright (c) 2017, Los Alamos National Security, LLC (LANS) +# and the University Corporation for Atmospheric Research (UCAR). +# +# Unless noted otherwise source code is licensed under the BSD license. +# Additional copyright and license information can be found in the LICENSE file +# distributed with this code, or at http://mpas-dev.github.com/license.html +# from __future__ import absolute_import, division, print_function, \ unicode_literals diff --git a/mpas_analysis/shared/html/templates/component_gallery.html b/mpas_analysis/shared/html/templates/component_gallery.html index a016c5e8f..ee0400a57 100644 --- a/mpas_analysis/shared/html/templates/component_gallery.html +++ b/mpas_analysis/shared/html/templates/component_gallery.html @@ -1,3 +1,13 @@ + + + @galleryTitle