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/README.md b/README.md index b3f208287..f3982d569 100644 --- a/README.md +++ b/README.md @@ -103,12 +103,19 @@ for more details. * `mpaso.rst.0002-01-01_00000.nc` (or any other mpas-o restart file) * `streams.ocean` * `mpas-o_in` - * mpas-cice files: - * `mpascice.hist.am.timeSeriesStatsMonthly.*.nc` - * `mpascice.rst.0002-01-01_00000.nc` (or any other mpas-cice restart + * mpas-seaice files: + * `mpasseaice.hist.am.timeSeriesStatsMonthly.*.nc` + * `mpasseaice.rst.0002-01-01_00000.nc` (or any other mpas-seaice restart file) - * `streams.cice` - * `mpas-cice_in` + * `streams.seaice` + * `mpas-seaice_in` + +Note: for older runs, mpas-seaice files will be named: + * `mpascice.hist.am.timeSeriesStatsMonthly.*.nc` + * `mpascice.rst.0002-01-01_00000.nc` + * `streams.cice` + * `mpas-cice_in` + ## Purge Old Analysis diff --git a/conda/recipe/build.sh b/conda/recipe/build.sh new file mode 100644 index 000000000..2249089f8 --- /dev/null +++ b/conda/recipe/build.sh @@ -0,0 +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/conda/recipe/meta.yaml b/conda/recipe/meta.yaml new file mode 100644 index 000000000..6403dae78 --- /dev/null +++ b/conda/recipe/meta.yaml @@ -0,0 +1,47 @@ +{% set version = "0.7.5" %} + +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 + 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..035d50c55 100644 --- a/configs/anvil/config.20170926.FCT2.A_WCYCL1850S.ne30_oECv3.anvil +++ b/configs/anvil/config.20170926.FCT2.A_WCYCL1850S.ne30_oECv3.anvil @@ -32,6 +32,13 @@ mpasMeshName = oEC60to30v3 # placed in the output mappingSubdirectory mappingDirectory = /lcrc/group/acme/mpas_analysis/mapping +# names of namelist and streams files, either a path relative to baseDirectory +# or an absolute path. +oceanNamelistFileName = mpas-o_in +oceanStreamsFileName = streams.ocean +seaIceNamelistFileName = mpas-cice_in +seaIceStreamsFileName = streams.cice + [output] ## options related to writing out plots, intermediate cached data sets, logs, ## etc. @@ -142,4 +149,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 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/config.20171201.default.GMPAS-IAF.T62_oRRS30to10v3wLI.cori-knl b/configs/cori/config.20171201.default.GMPAS-IAF.T62_oRRS30to10v3wLI.cori-knl index d7e31c660..e32a02ef0 100644 --- a/configs/cori/config.20171201.default.GMPAS-IAF.T62_oRRS30to10v3wLI.cori-knl +++ b/configs/cori/config.20171201.default.GMPAS-IAF.T62_oRRS30to10v3wLI.cori-knl @@ -43,6 +43,13 @@ mpasMeshName = oRRS30to10v3wLI # placed in the output mappingSubdirectory mappingDirectory = /global/project/projectdirs/acme/mpas_analysis/mapping +# names of namelist and streams files, either a path relative to baseDirectory +# or an absolute path. +oceanNamelistFileName = mpas-o_in +oceanStreamsFileName = streams.ocean +seaIceNamelistFileName = mpas-cice_in +seaIceStreamsFileName = streams.cice + [output] ## options related to writing out plots, intermediate cached data sets, logs, ## etc. 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/config.20170807.beta1.G_oQU240.edison b/configs/edison/config.20170807.beta1.G_oQU240.edison index 15176e615..a5ebc0465 100644 --- a/configs/edison/config.20170807.beta1.G_oQU240.edison +++ b/configs/edison/config.20170807.beta1.G_oQU240.edison @@ -32,6 +32,13 @@ mpasMeshName = oQU240 # placed in the output mappingSubdirectory # mappingDirectory = /dir/for/mapping/files +# names of namelist and streams files, either a path relative to baseDirectory +# or an absolute path. +oceanNamelistFileName = mpas-o_in +oceanStreamsFileName = streams.ocean +seaIceNamelistFileName = mpas-cice_in +seaIceStreamsFileName = streams.cice + [output] ## options related to writing out plots, intermediate cached data sets, logs, ## etc. diff --git a/configs/edison/config.20171102.beta3rc02_1850.ne30_oECv3_ICG.edison b/configs/edison/config.20171102.beta3rc02_1850.ne30_oECv3_ICG.edison index c98f76515..c4d7fb149 100644 --- a/configs/edison/config.20171102.beta3rc02_1850.ne30_oECv3_ICG.edison +++ b/configs/edison/config.20171102.beta3rc02_1850.ne30_oECv3_ICG.edison @@ -33,6 +33,13 @@ mpasMeshName = oEC60to30v3 # placed in the output mappingSubdirectory mappingDirectory = /global/project/projectdirs/acme/mpas_analysis/mapping +# names of namelist and streams files, either a path relative to baseDirectory +# or an absolute path. +oceanNamelistFileName = mpas-o_in +oceanStreamsFileName = streams.ocean +seaIceNamelistFileName = mpas-cice_in +seaIceStreamsFileName = streams.cice + [output] ## options related to writing out plots, intermediate cached data sets, logs, ## etc. diff --git a/configs/edison/config.B_low_res_ice_shelves_1696_JWolfe_layout_Edison b/configs/edison/config.B_low_res_ice_shelves_1696_JWolfe_layout_Edison index 8a76e16bd..3cb7742d2 100644 --- a/configs/edison/config.B_low_res_ice_shelves_1696_JWolfe_layout_Edison +++ b/configs/edison/config.B_low_res_ice_shelves_1696_JWolfe_layout_Edison @@ -43,6 +43,13 @@ mpasMeshName = oEC60to30v3wLI # placed in the output mappingSubdirectory mappingDirectory = /global/project/projectdirs/acme/mpas_analysis/mapping +# names of namelist and streams files, either a path relative to baseDirectory +# or an absolute path. +oceanNamelistFileName = mpas-o_in +oceanStreamsFileName = streams.ocean +seaIceNamelistFileName = mpas-cice_in +seaIceStreamsFileName = streams.cice + [output] ## options related to writing out plots, intermediate cached data sets, logs, ## etc. 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/config.20170207.MPAS-SeaIce.QU60km_polar.wolf b/configs/lanl/config.20170207.MPAS-SeaIce.QU60km_polar.wolf index 51cf6628f..d019a4c00 100644 --- a/configs/lanl/config.20170207.MPAS-SeaIce.QU60km_polar.wolf +++ b/configs/lanl/config.20170207.MPAS-SeaIce.QU60km_polar.wolf @@ -32,6 +32,13 @@ mpasMeshName = QU60 # placed in the output mappingSubdirectory # mappingDirectory = /dir/for/mapping/files +# names of namelist and streams files, either a path relative to baseDirectory +# or an absolute path. +oceanNamelistFileName = mpas-o_in +oceanStreamsFileName = streams.ocean +seaIceNamelistFileName = mpas-cice_in +seaIceStreamsFileName = streams.cice + [output] ## options related to writing out plots, intermediate cached data sets, logs, ## etc. diff --git a/configs/lanl/config.MatchBoth_orig b/configs/lanl/config.MatchBoth_orig index 2c04fc127..c0d36a3ee 100644 --- a/configs/lanl/config.MatchBoth_orig +++ b/configs/lanl/config.MatchBoth_orig @@ -32,6 +32,13 @@ mpasMeshName = oEC60to30v3 # placed in the output mappingSubdirectory mappingDirectory = /turquoise/usr/projects/climate/SHARED_CLIMATE/mpas_analysis/mapping/ +# names of namelist and streams files, either a path relative to baseDirectory +# or an absolute path. +oceanNamelistFileName = mpas-o_in +oceanStreamsFileName = streams.ocean +seaIceNamelistFileName = mpas-cice_in +seaIceStreamsFileName = streams.cice + [output] ## options related to writing out plots, intermediate cached data sets, logs, ## etc. 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/config.20170313.beta1.A_WCYCL1850S.ne30_oECv3_ICG.edison b/configs/olcf/config.20170313.beta1.A_WCYCL1850S.ne30_oECv3_ICG.edison index c4b567970..3d93c3a80 100644 --- a/configs/olcf/config.20170313.beta1.A_WCYCL1850S.ne30_oECv3_ICG.edison +++ b/configs/olcf/config.20170313.beta1.A_WCYCL1850S.ne30_oECv3_ICG.edison @@ -32,6 +32,13 @@ mpasMeshName = oEC60to30v3 # placed in the output mappingSubdirectory mappingDirectory = /lustre/atlas/proj-shared/cli115/mpas_analysis/mapping/ +# names of namelist and streams files, either a path relative to baseDirectory +# or an absolute path. +oceanNamelistFileName = mpas-o_in +oceanStreamsFileName = streams.ocean +seaIceNamelistFileName = mpas-cice_in +seaIceStreamsFileName = streams.cice + [output] ## options related to writing out plots, intermediate cached data sets, logs, ## etc. diff --git a/configs/olcf/config.GMPAS-IAF_oRRS18to6v3.titan b/configs/olcf/config.GMPAS-IAF_oRRS18to6v3.titan index b38ae1983..33585854f 100644 --- a/configs/olcf/config.GMPAS-IAF_oRRS18to6v3.titan +++ b/configs/olcf/config.GMPAS-IAF_oRRS18to6v3.titan @@ -32,6 +32,13 @@ mpasMeshName = oRRS18to6v3 # placed in the output mappingSubdirectory mappingDirectory = /lustre/atlas/proj-shared/cli115/mpas_analysis/mapping +# names of namelist and streams files, either a path relative to baseDirectory +# or an absolute path. +oceanNamelistFileName = mpas-o_in +oceanStreamsFileName = streams.ocean +seaIceNamelistFileName = mpas-cice_in +seaIceStreamsFileName = streams.cice + [output] ## options related to writing out plots, intermediate cached data sets, logs, ## etc. 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/config.20171031.tenYearTest.GMPAS-IAF.T62_oEC60to30v3wLI.60layer.theta b/configs/theta/config.20171031.tenYearTest.GMPAS-IAF.T62_oEC60to30v3wLI.60layer.theta index 2d87a8b84..190e7c374 100644 --- a/configs/theta/config.20171031.tenYearTest.GMPAS-IAF.T62_oEC60to30v3wLI.60layer.theta +++ b/configs/theta/config.20171031.tenYearTest.GMPAS-IAF.T62_oEC60to30v3wLI.60layer.theta @@ -45,6 +45,13 @@ mpasMeshName = oEC60to30v3wLI # placed in the output mappingSubdirectory mappingDirectory = /projects/OceanClimate/mpas-analysis_data/mpas_analysis/mapping +# names of namelist and streams files, either a path relative to baseDirectory +# or an absolute path. +oceanNamelistFileName = mpas-o_in +oceanStreamsFileName = streams.ocean +seaIceNamelistFileName = mpas-cice_in +seaIceStreamsFileName = streams.cice + [output] ## options related to writing out plots, intermediate cached data sets, logs, ## etc. 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/docs/.gitignore b/docs/.gitignore index 86d4c2dd3..1cc1ca4d3 100644 --- a/docs/.gitignore +++ b/docs/.gitignore @@ -1 +1,2 @@ generated +*_obs_table.rst diff --git a/docs/Makefile b/docs/Makefile index 1489bead0..609aaa947 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -12,9 +12,13 @@ BUILDDIR = _build help: @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) +clean: + rm -rf *observationstable.rst + @$(SPHINXBUILD) -M clean "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + .PHONY: help Makefile # Catch-all target: route all unknown targets to Sphinx using the new # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). %: Makefile - @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) \ No newline at end of file + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/__init__.py b/docs/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/docs/api.rst b/docs/api.rst index 5a240eff0..4aa18fc57 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -51,7 +51,12 @@ Ocean tasks ClimatologyMapSST ClimatologyMapSSS ClimatologyMapMLD + ClimatologyMapSSH ClimatologyMapAntarcticMelt + ClimatologyMapSoseTemperature + ClimatologyMapSoseSalinity + ClimatologyMapArgoTemperature + ClimatologyMapArgoSalinity IndexNino34 MeridionalHeatTransport StreamfunctionMOC diff --git a/docs/authors.rst b/docs/authors.rst new file mode 100644 index 000000000..5f5711aa6 --- /dev/null +++ b/docs/authors.rst @@ -0,0 +1,19 @@ +Main Authors +============ +* Xylar Asay-Davis +* Milena Veniziani +* Phillip J. 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 diff --git a/docs/conf.py b/docs/conf.py index d9a7031e7..658d713e2 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -16,6 +16,7 @@ import sys sys.path.insert(0, os.path.abspath('..')) import mpas_analysis +from docs.parse_table import build_rst_table_from_xml # -- General configuration ------------------------------------------------ @@ -57,7 +58,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, ' \ @@ -69,9 +70,9 @@ # built documents. # # The short X.Y version. -version = u'0.6.5' +version = u'0.7.5' # The full version, including alpha/beta/rc tags. -release = u'0.6.5' +release = u'0.7.5' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. @@ -181,3 +182,10 @@ 'python': ('https://docs.python.org/', None), 'numpy': ('http://docs.scipy.org/doc/numpy/', None), 'xarray': ('http://xarray.pydata.org/en/stable/', None)} + + +# Build some custom rst files +xmlFileName = '../mpas_analysis/obs/observational_datasets.xml' +for component in ['ocean', 'seaice']: + build_rst_table_from_xml(xmlFileName, '{}_obs_table.rst'.format(component), + component) \ 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/environment.yml b/docs/environment.yml index 3500fb5e4..694b5e6d6 100644 --- a/docs/environment.yml +++ b/docs/environment.yml @@ -21,5 +21,5 @@ dependencies: - sphinx - sphinx_rtd_theme - numpydoc - - pip: - - recommonmark + - tabulate >= 0.8.2 + - recommonmark diff --git a/docs/index.rst b/docs/index.rst index 1bdbce629..07e7ace11 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -14,7 +14,6 @@ Analysis for simulations produced with Model for Prediction Across Scales (MPAS) components and the Accelerated Climate Model for Energy (ACME), which used those components. - Documentation ============= .. toctree:: @@ -23,7 +22,30 @@ Documentation api design_docs +MPAS Components and E3SM +======================== + +.. toctree:: + :maxdepth: 2 + + mpaso + mpasseaice + e3sm + +Observational Data Sets +======================= +.. toctree:: + + observations + Indices and tables ================== -* :ref:`genindex` \ No newline at end of file +* :ref:`genindex` + +Authors +======= +.. toctree:: + :maxdepth: 1 + + authors 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. diff --git a/docs/mpasseaice.rst b/docs/mpasseaice.rst new file mode 100644 index 000000000..248209ad7 --- /dev/null +++ b/docs/mpasseaice.rst @@ -0,0 +1,63 @@ +MPAS-Seaice +============ + +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. + +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.seaice`` or ``mpas-seaice_in`` (or ``mpas-cice_in`` in +older E3SM runs):: + + 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.seaice`` or ``streams.cice`` in older E3SM runs, (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/observations.rst b/docs/observations.rst new file mode 100644 index 000000000..8c5ea35b6 --- /dev/null +++ b/docs/observations.rst @@ -0,0 +1,13 @@ +Observations +============ + +A variety of observational datasets are used within MPAS-Analysis: + +Ocean Observations +------------------ +.. include:: ocean_obs_table.rst + +Sea Ice Observations +-------------------- +.. include:: seaice_obs_table.rst + diff --git a/docs/parse_table.py b/docs/parse_table.py new file mode 100755 index 000000000..c44ab3c30 --- /dev/null +++ b/docs/parse_table.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python +""" +This script is used to convert an xml-based table into an rst table for +python documentation and pythonic parsing. + +Phillip J. Wolfram +04/16/2018 +""" + +import xml.etree.ElementTree as ET +import tabulate +import argparse +import re + + +def markdown_links(data, footer): + urlscmd = re.findall(r"\[.*?\]\n*\(.*?\)", data) + urls = re.findall(r"\[.*?\]\n*\((.*?)\)", data) + linknames = re.findall(r"\[(.*?)\]\n*\(.*?\)", data) + + for alinkname, aurl, aurlscmd in zip(linknames, urls, urlscmd): + data = data.replace(aurlscmd, '`' + alinkname + '`_') + footer += ".. _`" + alinkname + "`: " + aurl + "\n" + + return data, footer + + +def spurious_newline_whitespace(data, _): + whitespace = re.findall('\n\s*', data) + if len(whitespace) > 0: + astr = min(whitespace) + data = data.replace(astr, "\n") + return data, _ + + +def cleanup(linedata, footer): + cleanups = [spurious_newline_whitespace, markdown_links] + for acleanup in cleanups: + linedata, footer = acleanup(linedata, footer) + return linedata, footer + + +def build_rst_table_from_xml(xmlfile, rstfile, component): + + # open xml file for reading + xml = ET.parse(xmlfile) + + # open rst file for writing + rst = open(rstfile, 'w') + + # get headers and build list to write entries + headers = xml.getroot().attrib['headers'].replace(' ', '').split(',') + headernames = [aname.strip() for aname in + xml.getroot().attrib['headernames'].split(',')] + data = [] + footer = '' + for entry in xml.findall('observation'): + if (component != 'all' and + entry.findall('component')[0].text.strip() != component): + continue + line = [] + for aheader in headers: + linedata = entry.findall(aheader)[0].text.strip() + linedata, footer = cleanup(linedata, footer) + line.append(linedata) + data.append(line) + + rst.writelines(tabulate.tabulate(data, headernames, tablefmt='rst') + '\n') + rst.write('\n') + rst.write(footer) + rst.write('\n') + + rst.close() + + +if __name__ == "__main__": + parser = argparse.ArgumentParser( + description=__doc__, formatter_class=argparse.RawTextHelpFormatter) + parser.add_argument("-x", "--xml_table", dest="xml_table", + help="Path to file containing " + "xml description of table", + metavar="FILE", required=True) + parser.add_argument("-r", "--rst_table", dest="rst_table", + help="Path to file containing rst description " + "of table for output", + metavar="FILE", required=True) + parser.add_argument("-c", "--component", dest="component", + help="Component for parsing of table: " + "'landice', 'ocean', 'seaice', or 'all'", + metavar="STRING", default="all") + + args = parser.parse_args() + + build_rst_table_from_xml(args.xml_table, args.rst_table, args.component) 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..4439e578b --- /dev/null +++ b/licenses/_headers/license-bump-copyright.sh @@ -0,0 +1,64 @@ +#!/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) 2017, UT" +NEW="Copyright (c) 2017-2018, UT" + +echo "--------------------------------------------------------------------------------" +echo " THESE FILES HAVE AN OUTDATED LICENSE HEADER:" +echo "--------------------------------------------------------------------------------" +find ${SOURCE_DIR} -type f "${ALWAYS_IGNORE[@]}" \ + "${FILE_IGNORE[@]}" \ + "${PYTHON_IGNORE[@]}" \ + | xargs -r grep -l "$OLD" \ + | sort + +# Also, bump any copyright statements in the documentation +find ${SOURCE_DIR}/docs -type f \ + -not -path "*_build*" \ + -not -path "*source*" \ + "${FILE_IGNORE[@]}" \ + | xargs -r grep -l "$OLD" \ + | sort + + +echo "--------------------------------------------------------------------------------" +echo " UPDATING THE LICENSE HEADERS:" +echo "--------------------------------------------------------------------------------" +find ${SOURCE_DIR} -type f "${ALWAYS_IGNORE[@]}" \ + "${FILE_IGNORE[@]}" \ + | xargs -r grep -l "$OLD" \ + | sort \ + | while read SRC +do + echo "Bumping $SRC" + sed -i "s/$OLD/$NEW/g" ${SRC} +done + +# Also, bump any copyright statements in the documentation +find ${SOURCE_DIR}/docs -type f \ + -not -path "*_build*" \ + -not -path "*source*" \ + "${FILE_IGNORE[@]}" \ + | xargs -r 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..7b6ed7815 --- /dev/null +++ b/licenses/_headers/license-find-missing.sh @@ -0,0 +1,20 @@ +#!/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[@]}" \ + | xargs -r 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..c74062570 --- /dev/null +++ b/licenses/_headers/license-prepend-missing.sh @@ -0,0 +1,178 @@ +#!/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 " ATTEMPTING TO PREPEND A LICENSE HEADER ONTO THESE FILES:" +echo "--------------------------------------------------------------------------------" +find ${SOURCE_DIR} -type f "${ALWAYS_IGNORE[@]}" \ + "${FILE_IGNORE[@]}" \ + "${PYTHON_IGNORE[@]}" \ + | xargs -r grep -L "$CURRENT" \ + | sort + +echo "--------------------------------------------------------------------------------" +echo " BEGIN PREPENDING:" +echo "--------------------------------------------------------------------------------" + + +############################################################ +# Prepend license header to python files with a shebang and an encoding header. +# Will ignore files with a current license header. +############################################################ +GET=( -iname "*.py" ) + +find ${SOURCE_DIR} -type f \( "${GET[@]}" \) "${ALWAYS_IGNORE[@]}" "${PYTHON_IGNORE[@]}" \ + | xargs -r grep -l --max-count=1 "#!" \ + | xargs -r grep -l --max-count=1 "# -\*-" \ + | xargs -r grep -L "$CURRENT" \ + | while read SRC +do + BN=`basename ${SRC}` + echo HEADING ${SRC} + cat ${SRC} | head -n 2 > /tmp/licHead + cat header-py >> /tmp/licHead + cat ${SRC} | tail -n +3 >> /tmp/licHead + chmod --reference=${SRC} /tmp/licHead + mv /tmp/licHead ${SRC} +done + + +####################################################################### +# Prepend license header to python files with encoding header. +# Will ignore files with a current license header. +####################################################################### +GET=( -iname "*.py" ) + +find ${SOURCE_DIR} -type f \( "${GET[@]}" \) "${ALWAYS_IGNORE[@]}" "${PYTHON_IGNORE[@]}" \ + | xargs -r grep -l --max-count=1 "# -\*-" \ + | xargs -r grep -L "$CURRENT" \ + | while read SRC +do + BN=`basename ${SRC}` + echo HEADING ${SRC} + cat ${SRC} | head -n 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 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 -r grep -L "#!" \ + | xargs -r 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 -r grep -l --max-count=1 "#!" \ + | xargs -r 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 -r 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[@]}" \ + | xargs -r 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!" + + +MISSED=`find ${SOURCE_DIR} -type f "${ALWAYS_IGNORE[@]}" \ + "${FILE_IGNORE[@]}" \ + "${PYTHON_IGNORE[@]}" \ + | xargs -r grep -L "$CURRENT"` + +if [ "$MISSED" ] +then + echo "" + echo " WARNING: There is no method to prepend a license header onto the following" + echo " files. Please either manually add the license head to these files," + echo " add a method to prepend a license header onto these type of files," + echo " or set them to be ignored in 'license-setup.sh'. " + echo "--------------------------------------------------------------------------------" + find ${SOURCE_DIR} -type f "${ALWAYS_IGNORE[@]}" \ + "${FILE_IGNORE[@]}" \ + "${PYTHON_IGNORE[@]}" \ + | xargs -r grep -L "$CURRENT" \ + | sort + echo "--------------------------------------------------------------------------------" +else + echo "--------------------------------------------------------------------------------" +fi \ No newline at end of file diff --git a/licenses/_headers/license-setup.sh b/licenses/_headers/license-setup.sh new file mode 100755 index 000000000..21c26b0eb --- /dev/null +++ b/licenses/_headers/license-setup.sh @@ -0,0 +1,37 @@ +#!/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 "${SOURCE_DIR}/docs/*" \ + -not -path "${SOURCE_DIR}/licenses/*" \ + -not -path "${SOURCE_DIR}/build/*" \ + -not -path "${SOURCE_DIR}/dist/*" \ + -not -path "${SOURCE_DIR}/.idea/*" \ + -not -path "*.egg-info/*" \ + -not -path "${SOURCE_DIR}/conda/recipe/meta.yaml" \ + -not -path "${SOURCE_DIR}/setup.cfg") + +FILE_IGNORE=(-not -iname "*.ocean" -not -iname "*_in" \ + -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") diff --git a/mpas_analysis/analysis_task_template.py b/mpas_analysis/analysis_task_template.py index 2ec02f293..993205726 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`, @@ -27,11 +34,10 @@ to be generated and is set up properly. Don't forget to remove this docstring. (It's not needed.) - -Authors -------- -Xylar Asay-Davis ''' +# Authors +# ------- +# Xylar Asay-Davis from __future__ import absolute_import, division, print_function, \ unicode_literals @@ -42,11 +48,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 @@ -59,11 +66,10 @@ class MyTask(AnalysisTask): # {{{ ''' - - Authors - ------- - ''' + # Authors + # ------- + # # This function is the "constructor", which is called when you want to # create a new object from your class. Typically, it will just store a few @@ -106,12 +112,11 @@ def __init__(self, config, prerequsiteTask, myArg='myDefaultValue'): # {{{ myArg : str, optional - - Authors - ------- - - ''' + # Authors + # ------- + # + # first, call the constructor from the base class (AnalysisTask). # Modify MyTask, "myTask", "component" and ['tag1', 'tag2'] below: # taskName is the same as the class name but with a lowercase letter @@ -193,11 +198,10 @@ def setup_and_check(self): # {{{ Raises ------ ValueError: - - Authors - ------- - ''' + # Authors + # ------- + # # first, call setup_and_check from the base class (AnalysisTask), # which will perform some common setup, including storing: @@ -309,11 +313,10 @@ def setup_and_check(self): # {{{ def run_task(self): # {{{ ''' The main method of the task that performs the analysis task. - - Authors - ------- - ''' + # Authors + # ------- + # # Add the main contents of the analysis task below diff --git a/mpas_analysis/config.default b/mpas_analysis/config.default index a96053572..966d9c71f 100644 --- a/mpas_analysis/config.default +++ b/mpas_analysis/config.default @@ -74,8 +74,8 @@ seaIceHistorySubdirectory = . # or an absolute path. oceanNamelistFileName = mpas-o_in oceanStreamsFileName = streams.ocean -seaIceNamelistFileName = mpas-cice_in -seaIceStreamsFileName = streams.cice +seaIceNamelistFileName = mpas-seaice_in +seaIceStreamsFileName = streams.seaice # names of ocean and sea ice meshes (e.g. oEC60to30, oQU240, oRRS30to10, etc.) mpasMeshName = mesh @@ -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. @@ -212,6 +217,8 @@ ninoSubdirectory = Nino 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) @@ -321,6 +328,14 @@ preprocessedFieldPrefix = ohc # window) movingAveragePoints = 12 +# An optional first year for the tick marks on the x axis. Leare commented out +# to start at the beginning of the time series. +# firstYearXTicks = 1 + +# An optional number of years between tick marks on the x axis. Leave +# commented out to determine the distance between ticks automatically. +# yearStrideXTicks = 1 + [hovmollerOHCAnomaly] ## options related to time vs. depth Hovmoller plots of ocean heat content ## (OHC) anomalies from year 1 @@ -337,6 +352,15 @@ colorbarLevels = [-2.4, -0.8, -0.4, -0.2, 0, 0.2, 0.4, 0.8, 2.4] # contour line levels contourLevels = np.arange(-2.5, 2.6, 0.5) +# An optional first year for the tick marks on the x axis. Leare commented out +# to start at the beginning of the time series. + +# firstYearXTicks = 1 + +# An optional number of years between tick marks on the x axis. Leave +# commented out to determine the distance between ticks automatically. +# yearStrideXTicks = 1 + [hovmollerTemperatureAnomaly] ## options related to plotting time series of temperature vs. depth @@ -357,6 +381,16 @@ colorbarLevels = [-1, -0.5, -0.2, -0.05, 0, 0.05, 0.2, 0.5, 1] # contour line levels contourLevels = np.arange(-1.0, 1.26, 0.25) +# An optional first year for the tick marks on the x axis. Leare commented out +# to start at the beginning of the time series. + +# firstYearXTicks = 1 + +# An optional number of years between tick marks on the x axis. Leave +# commented out to determine the distance between ticks automatically. + +# yearStrideXTicks = 1 + [hovmollerSalinityAnomaly] ## options related to plotting time series of salinity vs. depth @@ -377,6 +411,16 @@ colorbarLevels = [-0.1, -0.02, -0.003, -0.001, 0, 0.001, 0.003, 0.02, 0.1] # contour line levels contourLevels = np.arange(-0.1, 0.11, 0.02) +# An optional first year for the tick marks on the x axis. Leare commented out +# to start at the beginning of the time series. + +# firstYearXTicks = 1 + +# An optional number of years between tick marks on the x axis. Leave +# commented out to determine the distance between ticks automatically. + +# yearStrideXTicks = 1 + [timeSeriesSST] ## options related to plotting time series of sea surface temperature (SST) @@ -389,6 +433,16 @@ regions = ['global'] # window) movingAveragePoints = 12 +# An optional first year for the tick marks on the x axis. Leare commented out +# to start at the beginning of the time series. + +# firstYearXTicks = 1 + +# An optional number of years between tick marks on the x axis. Leave +# commented out to determine the distance between ticks automatically. + +# yearStrideXTicks = 1 + [indexNino34] ## options related to plotting time series of the El Nino 3.4 index @@ -442,6 +496,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'] @@ -492,6 +551,16 @@ movingAveragePoints = 12 # latitude) for climatological MOC plots movingAveragePointsClimatological = 1 +# An optional first year for the tick marks on the x axis. Leare commented out +# to start at the beginning of the time series. + +# firstYearXTicks = 1 + +# An optional number of years between tick marks on the x axis. Leave +# commented out to determine the distance between ticks automatically. + +# yearStrideXTicks = 1 + [timeSeriesSeaIceAreaVol] ## options related to plotting time series of sea ice area and volume @@ -506,6 +575,16 @@ titleFontSize = 18 # plot on polar plot polarPlot = False +# An optional first year for the tick marks on the x axis. Leare commented out +# to start at the beginning of the time series. + +# firstYearXTicks = 1 + +# An optional number of years between tick marks on the x axis. Leave +# commented out to determine the distance between ticks automatically. + +# yearStrideXTicks = 1 + [climatologyMapSST] ## options related to plotting horizontally remapped climatologies of ## sea surface temperature (SST) against reference model results and @@ -521,9 +600,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 +625,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 +650,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) @@ -582,6 +661,42 @@ 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 +colormapNameResult = Maximenko +# color indices into colormapName for filled contours +colormapIndicesResult = numpy.array(numpy.linspace(0, 255, 38), int) +# colormap levels/values for contour boundaries +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 +# 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 = [-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) +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 @@ -625,6 +740,16 @@ iceShelvesToPlot = ['Antarctica'] # Number of months over which to compute moving average movingAverageMonths = 1 +# An optional first year for the tick marks on the x axis. Leare commented out +# to start at the beginning of the time series. + +# firstYearXTicks = 1 + +# An optional number of years between tick marks on the x axis. Leave +# commented out to determine the distance between ticks automatically. + +# yearStrideXTicks = 1 + [climatologyMapSoseTemperature] ## options related to plotting climatology maps of Antarctic ## potential temperature at various levels, including the sea floor against @@ -661,6 +786,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. Argo data is only available above -2000 m +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 @@ -696,6 +856,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. Argo data is only available above -2000 m +depths = ['top', -25, -50, -100, -150, -200, -400, -600, -800, -1500] + +# 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 @@ -711,9 +905,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 +941,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) 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/configuration/mpas_analysis_config_parser.py b/mpas_analysis/configuration/mpas_analysis_config_parser.py index 3bf3cf643..7cfae363c 100644 --- a/mpas_analysis/configuration/mpas_analysis_config_parser.py +++ b/mpas_analysis/configuration/mpas_analysis_config_parser.py @@ -1,13 +1,19 @@ +# 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 (``getWithDefault(section, option, default, ...)``) and to get options that are lists, tuples, dicts, etc (``getExpression(section, option)``). - -Authors -------- -Xylar Asay-Davis, Phillip J. Wolfram """ +# Authors +# ------- +# Xylar Asay-Davis, Phillip J. Wolfram from __future__ import absolute_import, division, print_function, \ unicode_literals @@ -22,8 +28,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): @@ -46,11 +52,11 @@ def getWithDefault(self, section, option, default): to determine the type of the option if it *is* found. If ``default`` is a list, tuple, or dict, ``getExpression(...)`` is used if the option is present in the config file. - - Authors - ------- - Xylar Asay-Davis """ + # Authors + # ------- + # Xylar Asay-Davis + if self.has_section(section): if self.has_option(section, option): if isinstance(default, bool): @@ -94,11 +100,11 @@ def getExpression(self, section, option, elementType=None, If ``True``, the expression is evaluated including functionality from the numpy package (which can be referenced either as ``numpy`` or ``np``). - - Authors - ------- - Xylar Asay-Davis, Phillip J. Wolfram """ + # Authors + # ------- + # Xylar Asay-Davis, Phillip J. Wolfram + expressionString = self.get(section, option) if usenumpyfunc: assert '__' not in expressionString, \ diff --git a/mpas_analysis/obs/observational_datasets.xml b/mpas_analysis/obs/observational_datasets.xml new file mode 100644 index 000000000..a5d5675ba --- /dev/null +++ b/mpas_analysis/obs/observational_datasets.xml @@ -0,0 +1,957 @@ + + + + + + + + SST merged Hadley Center-NOAA/OI data set + + + ocean + + + The merged Hadley-OI sea surface temperature (SST) and sea ice + concentration (SIC) data sets were specifically developed as surface + forcing data sets for AMIP style uncoupled simulations of the Community + Atmosphere Model (CAM). The Hadley Centre's SST/SIC version 1.1 + (HADISST1), which is derived gridded, bias-adjusted in situ observations, + were merged with the NOAA-Optimal Interpolation (version 2; OI.v2) + analyses. The HADISST1 spanned 1870 onward but the OI.v2, which started + in November 1981, better resolved features such as the Gulf Stream and + Kuroshio Current which are important components of the climate system. + Since the two data sets used different development methods, anomalies + from a base period were used to create a more homogeneous record. Also, + additional adjustments were made to the SIC data set. + + + [NCAR Hadley-NOAA/OI SST website] + (https://climatedataguide.ucar.edu/climate-data/merged-hadley-noaaoi-sea-surface-temperature-sea-ice-concentration-hurrell-et-al-2008) + + + Acknowledgment: Hurrell, J. W., J. J. Hack, D. Shea, J. M. Caron, and J. Rosinski, + 2008: A New Sea Surface Temperature and Sea Ice Boundary Dataset for the Community + Atmosphere Model. Journal of Climate, 21, 5145-5153. + + + [Hurrell et al. (2008)](https://doi.org/10.1175/2008JCLI2292.1) + + + @article{Hurrell2008, + author = {James W. Hurrell and James J. Hack and Dennis Shea and Julie M. Caron and James Rosinski}, + title = {A New Sea Surface Temperature and Sea Ice Boundary Dataset for the Community Atmosphere Model}, + journal = {Journal of Climate}, + volume = {21}, + number = {19}, + pages = {5145-5153}, + year = {2008}, + doi = {10.1175/2008JCLI2292.1}, + URL = {https://doi.org/10.1175/2008JCLI2292.1} + } + + + - ftp://ftp.cgd.ucar.edu/archive/SSTICE/MODEL.SST.HAD187001-198110.OI198111-201712.nc + + + + + - climatologyMapSST + + + + + + SSS from NASA Aquarius satellite + + + ocean + + + Level 3 Aquarius sea surface salinity (SSS) data products have a temporal + resolutions of daily, 8 day, monthly, 3 months, and annual. Monthly and + seasonal climatology + products from Aqaurius are also available. The Aquarius instrument + provides global coverage every 7 days. L3 products are gridded at 1 + degree spatial resolution. + + + [NASA Aquarius Website] + (https://podaac.jpl.nasa.gov/dataset/AQUARIUS_L4_OISSS_IPRC_7DAY_V4) + + + + NASA data are not copyrighted; however, when you publish our data or + results derived therefrom, we request that you include an acknowledgment + within the text of the publication and reference list. + [Data Citation and Acknowledgements] + (https://podaac.jpl.nasa.gov/CitingPODAAC) + + + [Lagerloef et al. (2015)](ftp://podaac.jpl.nasa.gov/SalinityDensity/aquarius/docs/v4/AQ-014-PS-0016_AquariusSalinityDataValidationAnalysis_DatasetVersion4.0and3.0.pdf) + + + + + ftp://podaac-ftp.jpl.nasa.gov/allData/aquarius/L4/IPRC/v4/7day/ + + + (missing) + + + - climatologyMapSSS + + + + + + AVISO Absolute Dynamic Topography + + + ocean + + + [NASA JPL AVISO website](https://podaac.jpl.nasa.gov/dataset/AVISO_L4_DYN_TOPO_1DEG_1MO) + This dataset contains absolute dynamic topography (similar to sea level + but with respect to the geoid) binned and averaged monthly on 1 degree + grids. The coverage is from October 1992 to December 2010. These data + were provided by AVISO (French space agency data provider) to support the + CMIP5 (Coupled Model Intercomparison Project Phase 5) under the World + Climate Research Program (WCRP) and was first made available via the JPL + Earth System Grid. The dynamic topography are derived from sea surface + height measured by several satellites including Envisat, TOPEX/Poseidon, + Jason-1 and OSTM/Jason-2, and referenced to the geoid. Along with this + dataset, two additional ancillary data files are included in the same + directory which contain the number of observations and standard error + co-located on the same 1 degree grids. + + + - [NASA JPL AVISO website](https://podaac.jpl.nasa.gov/dataset/AVISO_L4_DYN_TOPO_1DEG_1MO) + + + When using Ssalto/Duacs data (NRT or DT along-track Absolute Dynamic + Topography (ADT), maps of SLA geostrophic currents (MSLA UV) or maps of + ADT heights and currents (MADT H and UV), climatologies and averages of + MSLA-H), please cite: "The altimeter products were produced by + Ssalto/Duacs and distributed by Aviso, with support from Cnes + (http://www.aviso.altimetry.fr/duacs/)" + + + [AVISO: Sea Surface Height above Geoid] + (ftp://podaac.jpl.nasa.gov/allData/aviso/L4/dynamic_topo_1deg_1mo/docs/zosTechNote_AVISO_L4_199210-201012.pdf) + + + + + - ftp://podaac-ftp.jpl.nasa.gov/allData/aviso/L4/dynamic_topo_1deg_1mo/zos_AVISO_L4_199210-201012.nc + + + + + - climatologyMapSSH + + + + + + Argo Mixed Layer Depth (MLD) climatology + + + ocean + + + A mixed layer climatology and database (described in Holte et al. 2017) + using Argo profiles and a hybrid method (Holte and Talley 2009) for + finding the mixed layer depth (MLD). The climatology incorporates over + 1,385,000 Argo profiles (through February 2017). The new hybrid algorithm + models the general shape of each profile, searches for physical features + in the profile, and calculates threshold and gradient MLDs to assemble a + suite of possible MLD values. It then analyzes the patterns in the suite + to select a final MLD estimate. Results are also presented for MLDs + calculated using de Boyer Montegut et al.'s (2004) threshold values. + + + [UCSD Mixed Layer Website](http://mixedlayer.ucsd.edu/) + + + [Acknowledgment:](http://mixedlayer.ucsd.edu/) If you use this data, + please cite it as: Holte, J., L. D. Talley, J. Gilson, and D. Roemmich + (2017), An Argo mixed layer climatology and database, Geophys. Res. + Lett., 44, 5618–5626, doi:10.1002/2017GL073426. + + + - [Holte et al. (2017)](http://onlinelibrary.wiley.com/doi/10.1002/2017GL073426/full) + - [Holte and Talley (2009)](http://journals.ametsoc.org/doi/abs/10.1175/2009JTECHO543.1) + - [de Boyer Montegut et al. (2004)](https://agupubs.onlinelibrary.wiley.com/doi/abs/10.1029/2004JC002378) + + + @article{Holte2017, + author = {James Holte and Lynne D. Talley and John Gilson and Dean Roemmich}, + title = {An Argo mixed layer climatology and database}, + journal = {Geophysical Research Letters}, + year = {2017}, + volume = {44}, + number = {11}, + pages = {5618-5626}, + keywords = {Argo, mixed layer, climatology, global}, + doi = {10.1002/2017GL073426}, + url = {https://agupubs.onlinelibrary.wiley.com/doi/abs/10.1002/2017GL073426} + } + + @article{Holte2009, + author = { James Holte and Lynne Talley }, + title = {A New Algorithm for Finding Mixed Layer Depths with Applications to Argo Data and Subantarctic Mode Water Formation}, + journal = {Journal of Atmospheric and Oceanic Technology}, + volume = {26}, + number = {9}, + pages = {1920-1939}, + year = {2009}, + doi = {10.1175/2009JTECHO543.1}, + URL = {https://doi.org/10.1175/2009JTECHO543.1} + } + + @article{deBoyerMontegut2004, + author = {Cl\'{e}ment {de Boyer Mont\'{e}gut} and Gurvan Madec and Albert S. Fischer and Alban Lazar and Daniele Iudicone}, + title = {Mixed layer depth over the global ocean: An examination of profile data and a profile‐based climatology}, + journal = {Journal of Geophysical Research: Oceans}, + volume = {109}, + number = {C12}, + pages = {}, + year = {2004}, + keywords = {mixed layer, mixed layer depth criterion, density compensation}, + doi = {10.1029/2004JC002378}, + url = {https://agupubs.onlinelibrary.wiley.com/doi/abs/10.1029/2004JC002378} + } + + + - http://mixedlayer.ucsd.edu/data/Argo_mixedlayers_monthlyclim_03192017.nc + + + + + - climatologyMapMLD + + + + + + Meridional Heat Transport (MHT) + + + ocean + + + (missing) + + + (missing) + + + (missing) + + + [Trenberth and Caron (2000)](https://doi.org/10.1175/1520-0442%282000%29013<4358%3ATSORSL>2.0.CO%3B2) + + + @article{Trenberth2000, + author = { Kevin E. Trenberth and Julie M. Caron }, + title = {The Southern Oscillation Revisited: Sea Level Pressures, Surface Temperatures, and Precipitation}, + journal = {Journal of Climate}, + volume = {13}, + number = {24}, + pages = {4358-4365}, + year = {2000}, + doi = {10.1175/1520-0442(2000)013<4358:TSORSL>2.0.CO;2}, + URL = {https://doi.org/10.1175/1520-0442(2000)013<4358:TSORSL>2.0.CO;2} + } + + + (missing) + + + (missing) + + + - meridionalHeatTransport + + + + + + Roemmich-Gilson Argo Climatology + + + ocean + + + This new version of the Roemmich-Gilson Argo Climatology extends the + analysis of Argo-only derived temperature and salinity fields through + 2016. Several marginal seas and the Artic Oean have been added. The + analysis method is similar to what was descibed in the Progress In + Oceanography Roemmich and Gilson paper (2009). The only modification has + been to scale the zonal equatorial correlation of the optimal estimation + step, by 8 times, versus 4 times as in the 2009 paper. The additional + Argo data utilized in the analysis results in a longer monthly record as + well as better estimates of the mean and variability fields. Monthly + updates are available in between major yearly re-analyses. + + + [Scripps Roemmich-Gilson Argo Website](http://sio-argo.ucsd.edu/RG_Climatology.html) + + + [Acknowledgment:](http://sio-argo.ucsd.edu/RG_Climatology.html) Roemmich, + D. and J. Gilson, 2009: The 2004-2008 mean and annual cycle of + temperature, salinity, and steric height in the global ocean from the + Argo Program. Progress in Oceanography, 82, 81-100. + + + [Roemmich and Gilson (2009)](http://www.sciencedirect.com/science/article/pii/S0079661109000160) + + + @article{Roemmich2009, + title = "The 2004–2008 mean and annual cycle of temperature, salinity, and steric height in the global ocean from the Argo Program", + journal = "Progress in Oceanography", + volume = "82", + number = "2", + pages = "81 - 100", + year = "2009", + issn = "0079-6611", + doi = "10.1016/j.pocean.2009.03.004", + url = "http://www.sciencedirect.com/science/article/pii/S0079661109000160", + author = "Dean Roemmich and John Gilson" + } + + + - ftp://kakapo.ucsd.edu/pub/gilson/argo_climatology/RG_ArgoClim_Temperature_2017.nc.gz + - ftp://kakapo.ucsd.edu/pub/gilson/argo_climatology/RG_ArgoClim_Salinity_2017.nc.gz + + + preprocess_observations/Process_RG_Argo_climatology.ipynb + + + - climatologyMapArgoTemperature + - climatologyMapArgoSalinity + + + + + + SOSE potential temperature and salinity + + + ocean + + + Monthly potential temperature and salinity output from the Southern Ocean + State Estimate (SOSE) covering years 2005-2010 + + + [SOSE Website at UCSD] + (http://sose.ucsd.edu/sose_stateestimation_data_05to10.html) + + + [Conditions of use] + (http://sose.ucsd.edu/sose_stateestimation_disclaimer.html): The data on + these webpages are made freely available for scientific, bona fide, + not-for-profit research only. If your use of the data is different (e.g. + commercial), you must contact the data providers and receive written + permission for your use of the data prior to any such use. The user must + acknowledge SOSE data in all products or publications that use them, e.g. + by including the following written note: "Computational resources for the + SOSE were provided by NSF XSEDE resource grant OCE130007." An appropriate + citation should also be made. + + + [Mazloff et al. (2010)](http://doi.org/10.1175/2009JPO4236.1) + + + @article{Mazloff2010, + author = {Matthew R. Mazloff and Patrick Heimbach and Carl Wunsch}, + title = {An Eddy-Permitting Southern Ocean State Estimate}, + journal = {Journal of Physical Oceanography}, + volume = {40}, + number = {5}, + pages = {880-899}, + year = {2010}, + doi = {10.1175/2009JPO4236.1}, + URL = {https://doi.org/10.1175/2009JPO4236.1} + } + + + - http://sose.ucsd.edu/DATA/SO6_V2/THETA_mnthlyBar.0000000100.data.gz + - http://sose.ucsd.edu/DATA/SO6_V2/THETA_mnthlyBar.0000000100.meta + - http://sose.ucsd.edu/DATA/SO6_V2/SALT_mnthlyBar.0000000100.data.gz + - http://sose.ucsd.edu/DATA/SO6_V2/SALT_mnthlyBar.0000000100.meta + + + preprocess_observations/remap_SOSE_T_S.py + + + - climatologyMapSoseTemperature + - climatologyMapSoseSalinity + + + + + + Antarctic melt rates and fluxes + + + ocean + + + Melt rates and melt fluxes from Rignot et al. (2013) + + + [Ice-Shelf Melting Around Antarctica](http://science.sciencemag.org/content/341/6143/266) + + + Data available upon request from co-author J. Mouginot. + + + [Rignot et al. (2013)](http://science.sciencemag.org/content/341/6143/266) + + + @article{Rignot2013, + title = {Ice-{Shelf} {Melting} {Around} {Antarctica}}, + volume = {341}, + url = {http://www.ncbi.nlm.nih.gov/pubmed/23765278}, + doi = {10.1126/science.1235798}, + number = {6143}, + journal = {Science}, + author = {Rignot, E. and Jacobs, S. and Mouginot, J. and Scheuchl, B.}, + month = jul, + year = {2013}, + pages = {266--270} + } + + + - http://science.sciencemag.org/highwire/filestream/594977/field_highwire_adjunct_files/0/1235798tableS1.xlsx + - (data available upon request from J. Mouginot) + + + preprocess_observations/remap_rignot.py + + + - climatologyMapAntarcticMelt + - timeSeriesAntarcticMelt + + + + + + HadISST Nino 3.4 Index + + + ocean + + + (missing) + + + (missing) + + + (missing) + + + (missing) + + + (missing) + + + (missing) + + + (missing) + + + - indexNino34 + + + + + + ERS SSTv4 Nino 3.4 Index + + + ocean + + + (missing) + + + (missing) + + + (missing) + + + (missing) + + + (missing) + + + (missing) + + + (missing) + + + - indexNino34 + + + + + + + + + + Ice concentration: SSM/I, NASATeam algorithm + + + seaice + + + This data set is generated from brightness temperature data and is + designed to provide a consistent time series of sea ice concentrations + spanning the coverage of several passive microwave instruments. The data + are provided in the polar stereographic projection at a grid cell size of + 25 x 25 km. + + + [NSIDC NASATeam Website](http://nsidc.org/data/NSIDC-0051) + + + NASA data are not copyrighted; however, when you publish our data or + results derived therefrom, we request that you include an acknowledgment + within the text of the publication and reference list. + [Data Citation and Acknowledgements] + (https://podaac.jpl.nasa.gov/CitingPODAAC) + + + [Cavalieri et al. (1996)](https://doi.org/10.5067/8GQ8LZQVL0VL) + + + @misc{Cavalieri1996, + author = {D. J. Cavalieri, and C. L. Parkinson and P. Gloersen and H. J. Zwally}, + title = {Sea Ice Concentrations from Nimbus-7 SMMR and DMSP SSM/I-SSMIS Passive Microwave Data, Version 1}, + year = {1996}, + doi = {10.5067/8GQ8LZQVL0VL}, + notes = {updated yearly}, + url = {https://doi.org/10.5067/8GQ8LZQVL0VL} + } + + + (missing, requires registration with NSIDC) + + + preprocess_observations/NASATeam_Antarctic_compute_climo.m + preprocess_observations/NASATeam_Arctic_compute_climo.m + (missing remapping from stereographic to lat/lon) + + + - climatologyMapSeaIceConcNH + - climatologyMapSeaIceConcSH + + + + + + Ice concentration: SSM/I, Bootstrap algorithm + + + seaice + + + This sea ice concentration data set was derived using measurements from + the Scanning Multichannel Microwave Radiometer (SMMR) on the Nimbus-7 + satellite and from the Special Sensor Microwave/Imager (SSM/I) sensors on + the Defense Meteorological Satellite Program's (DMSP) -F8, -F11, and -F13 + satellites. Measurements from the Special Sensor Microwave Imager/Sounder + (SSMIS) aboard DMSP-F17 are also included. The data set has been + generated using the Advanced Microwave Scanning Radiometer - Earth + Observing System (AMSR-E) Bootstrap Algorithm with daily varying + tie-points. Daily (every other day prior to July 1987) and monthly data + are available for both the north and south polar regions. Data are + gridded on the SSM/I polar stereographic grid (25 x 25 km) and provided + in two-byte integer format. Data are available via FTP. + + + [NSIDC Bootstrap Website](http://nsidc.org/data/NSIDC-0079) + + + NASA data are not copyrighted; however, when you publish our data or + results derived therefrom, we request that you include an acknowledgment + within the text of the publication and reference list. + [Data Citation and Acknowledgements] + (https://podaac.jpl.nasa.gov/CitingPODAAC) + + + [Comiso (2017)](https://doi.org/10.5067/7Q8HCCWS4I0R) + + + @misc{Comiso1996, + author = {J. C. Comiso}, + title = {Bootstrap Sea Ice Concentrations from Nimbus-7 SMMR and DMSP SSM/I-SSMIS, Version 3}, + year = {2017}, + doi = {10.5067/7Q8HCCWS4I0R}, + notes = {updated yearly}, + url = {https://doi.org/10.5067/7Q8HCCWS4I0R} + } + + + (missing, requires registration with NSIDC) + + + preprocess_observations/Bootstrap_Antarctic_compute_climo.m + preprocess_observations/Bootstrap_Arctic_compute_climo.m + (missing remapping from stereographic to lat/lon) + + + - climatologyMapSeaIceConcNH + - climatologyMapSeaIceConcSH + + + + + + Ice area and extent time series: SSM/I derived + + + seaice + + + The sea ice data presented here were derived from satellite + passive-microwave radiometers, specifically, the Scanning Multichannel + Microwave Radiometer (SMMR) on NASA's Nimbus 7 satellite, for November + 1978-August 1987, a sequence of Special Sensor Microwave Imagers (SSMIs) + on the F8, F11, and F13 satellites of the Defense Meteorological + Satellite Program (DMSP), for August 1987-December 2007, and the Special + Sensor Microwave Imager Sounder (SSMIS) on the DMSP F17 satellite for + January 2008-December 2012. The baseline data used were daily maps of + sea ice concentration. The maps are polar stereographic projections with + individual grid elements of approximately 25 km x 25 km; and the ice + concentration data are also archived at the National Snow and Ice Data + Center (NSIDC) at http://nsidc.org. The concentrations are calculated for + each ocean grid element and are used to derive 'sea ice extent', which is + calculated as the sum of all ocean elements having a sea ice + concentration of at least 15%, and 'sea ice area', which is calculated as + the sum over all ocean grid elements of the product of ice concentration + and grid element area. The data sets provided here include the + hemispheric totals and additionally the values for nine regions in the + Arctic and five regions in the Antarctic. These regions are identified in + Figures 1 and 2 respectively. Figures 3 and 4 provide plots of the trends + in the Arctic and Antarctic sea ice extents, along with monthly + deviations and 12-month running means. The monthly deviations are + calculated by taking the individual month's ice extent/area and + subtracting from it the average over the course of the data set of the + extents/areas for that month. + + + [NASA Ice area and extent website](https://neptune.gsfc.nasa.gov/csb/index.php?section=59) + + + NASA data are not copyrighted; however, when you publish our data or + results derived therefrom, we request that you include an acknowledgment + within the text of the publication and reference list. + [Data Citation and Acknowledgements] + (https://podaac.jpl.nasa.gov/CitingPODAAC) + + + - [Cavalieri et al. (1999)](https://doi.org/10.1029/1999JC900081) + - [Cavalieri et al. (2012)](https://doi.org/10.1109/LGRS.2011.2166754) + - [Cavalieri and Parkinson (2012)](https://doi.org/10.5194/tc-6-881-2012) + - [Parkinson et al. (1999)](https://doi.org/0.1029/1999JC900082) + - [Parkinson and Cavalieri (2012)](https://doi.org/10.5194/tc-6-871-2012) + - [Zwally et al. (2002)](https://doi.org/10.1029/2000JC000733) + + + @article{Cavalieri1999, + author = {D. J. Cavalieri and C. L. Parkinson and P. Gloersen and J. C. Comiso and H. J. Zwally}, + title = {Deriving long‐term time series of sea ice cover from satellite passive‐microwave multisensor data sets}, + journal = {Journal of Geophysical Research: Oceans}, + volume = {104}, + number = {C7}, + year = {1999}, + pages = {15803-15814}, + doi = {10.1029/1999JC900081}, + url = {https://agupubs.onlinelibrary.wiley.com/doi/abs/10.1029/1999JC900081} + } + @article{Cavalieri2012a, + author={D. J. Cavalieri and C. L. Parkinson and N. DiGirolamo and A. Ivanoff}, + journal={IEEE Geoscience and Remote Sensing Letters}, + title={Intersensor Calibration Between F13 SSMI and F17 SSMIS for Global Sea Ice Data Records}, + year={2012}, + volume={9}, + number={2}, + pages={233-236}, + doi={10.1109/LGRS.2011.2166754}, + ISSN={1545-598X}, + month={March} + } + @Article{Cavalieri2012b, + AUTHOR = {Cavalieri, D. J. and Parkinson, C. L.}, + TITLE = {Arctic sea ice variability and trends, 1979--2010}, + JOURNAL = {The Cryosphere}, + VOLUME = {6}, + YEAR = {2012}, + NUMBER = {4}, + PAGES = {881--889}, + URL = {https://www.the-cryosphere.net/6/881/2012/}, + DOI = {10.5194/tc-6-881-2012} + } + @article{Parkinson1999, + author = {Claire L. Parkinson and Donald J. Cavalieri and Per Gloersen and H. Jay Zwally and Josefino C. Comiso}, + title = {Arctic sea ice extents, areas, and trends, 1978–1996}, + journal = {Journal of Geophysical Research: Oceans}, + volume = {104}, + number = {C9}, + year = {1999}, + pages = {20837-20856}, + doi = {10.1029/1999JC900082}, + url = {https://agupubs.onlinelibrary.wiley.com/doi/abs/10.1029/1999JC900082} + } + @Article{Parkinson2012, + AUTHOR = {Parkinson, C. L. and Cavalieri, D. J.}, + TITLE = {Antarctic sea ice variability and trends, 1979--2010}, + JOURNAL = {The Cryosphere}, + VOLUME = {6}, + YEAR = {2012}, + NUMBER = {4}, + PAGES = {871--880}, + URL = {https://www.the-cryosphere.net/6/871/2012/}, + DOI = {10.5194/tc-6-871-2012} + } + @article{Zwally2002, + author = {H. Jay Zwally and Josefino C. Comiso and Claire L. Parkinson and Donald J. Cavalieri and Per Gloersen}, + title = {Variability of Antarctic sea ice 1979–1998}, + journal = {Journal of Geophysical Research: Oceans}, + volume = {107}, + number = {C5}, + pages = {9-1-9-19}, + keywords = {sea ice, Antarctic, climate, passive microwave, Southern Ocean}, + doi = {10.1029/2000JC000733}, + url = {https://agupubs.onlinelibrary.wiley.com/doi/abs/10.1029/2000JC000733}, + year = {2002} + } + + + - https://neptune.gsfc.nasa.gov/uploads/files/NH_IceArea_Monthly_1978-2012.txt + - https://neptune.gsfc.nasa.gov/uploads/files/NH_IceExt_Monthly_1978-2012.txt + - https://neptune.gsfc.nasa.gov/uploads/files/SH_IceArea_Monthly_1978-2012.txt + - https://neptune.gsfc.nasa.gov/uploads/files/SH_IceExt_Monthly_1978-2012.txt + + + preprocess_observations/IceaArea_txt2netcdf.m + + + - timeSeriesSeaIceAreaVol + + + + + + IceSat Ice Thickness + + + seaice + + + This data set provides measurements of sea ice freeboard and sea ice + thickness for the Arctic region. The data were derived from measurements + made by from the Ice, Cloud, and land Elevation Satellite (ICESat) + Geoscience Laser Altimeter System (GLAS) instrument, the Special Sensor + Microwave/Imager (SSM/I), and climatologies of snow and drift of ice. + + + [NASA: Arctic Sea Ice Freeboard and Thickness](http://nsidc.org/data/NSIDC-0393) + + + NASA data are not copyrighted; however, when you publish our data or + results derived therefrom, we request that you include an acknowledgment + within the text of the publication and reference list. + [Data Citation and Acknowledgements] + (https://podaac.jpl.nasa.gov/CitingPODAAC) + + + [Yi and Zwally (2009)](https://doi.org/10.5067/SXJVJ3A2XIZT) + + + @misc{Yi2009, + author = {D. Yi and H. J. Zwally}, + title = {Arctic Sea Ice Freeboard and Thickness, Version 1}, + year = {2009}, + doi = {10.5067/7Q8HCCWS4I0R}, + url = {https://doi.org/10.5067/SXJVJ3A2XIZT} + } + + + (missing, requires registration with NSIDC) + + + ICESat_Arctic_compute_climo.m + (missing Antarctic climo) + (missing remapping from stereographic to lat/lon) + + + - timeSeriesSeaIceAreaVol + + + + + + PIOMAS Arctic Sea Ice Volume Reanalysis + + + seaice + + + Sea Ice Volume is calculated using the Pan-Arctic Ice Ocean Modeling and + Assimilation System (PIOMAS, Zhang and Rothrock, 2003) developed at + APL/PSC. Anomalies for each day are calculated relative to the average + over the 1979 -2016 period for that day of the year to remove the annual + cycle. The model mean annual cycle of sea ice volume over this period + ranges from 28,000 km3 in April to 11,500 km3 in September. + + + [PIOMAS website](http://psc.apl.uw.edu/research/projects/arctic-sea-ice-volume-anomaly/) + + + Data is public, but they optionally ask for basic information about the + person downloading the data (name, e-mail, and affiliation). + + + - [Schweiger et al. (2011)](https://doi.org/10.1029/2011JC007084) + - [Zhang and Rothrock (2003)](https://doi.org/10.1175/1520-0493%282003%29131<0845:MGSIWA>2.0.CO;2) + + + @article{Schweiger2011, + author = {Axel Schweiger and Ron Lindsay and Jinlun Zhang and Mike Steele and Harry Stern and Ron Kwok}, + title = {Uncertainty in modeled Arctic sea ice volume}, + journal = {Journal of Geophysical Research: Oceans}, + volume = {116}, + number = {C8}, + pages = {}, + keywords = {Arctic, climate change, ice volume, modelling, sea ice}, + doi = {10.1029/2011JC007084}, + url = {https://agupubs.onlinelibrary.wiley.com/doi/abs/10.1029/2011JC007084}, + year = {2011} + } + @article{Zhang2003, + author = { Jinlun Zhang and D. A. Rothrock }, + title = {Modeling Global Sea Ice with a Thickness and Enthalpy Distribution Model in Generalized Curvilinear Coordinates}, + journal = {Monthly Weather Review}, + volume = {131}, + number = {5}, + pages = {845-861}, + year = {2003}, + doi = {10.1175/1520-0493(2003)131<0845:MGSIWA>2.0.CO;2}, + URL = {https://doi.org/10.1175/1520-0493(2003)131<0845:MGSIWA>2.0.CO;2} + } + + + - http://psc.apl.uw.edu/wordpress/wp-content/uploads/schweiger/ice_volume/PIOMAS.2sst.monthly.Current.v2.1.txt + + + preprocess_observations/PIOMAS_txt2netcdf.m + + + - timeSeriesSeaIceAreaVol + + + + + + + + + diff --git a/mpas_analysis/ocean/__init__.py b/mpas_analysis/ocean/__init__.py index a9e4f9c89..f6f53384b 100644 --- a/mpas_analysis/ocean/__init__.py +++ b/mpas_analysis/ocean/__init__.py @@ -1,16 +1,24 @@ -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_ssh import ClimatologyMapSSH +from mpas_analysis.ocean.climatology_map_antarctic_melt import \ + ClimatologyMapAntarcticMelt +from mpas_analysis.ocean.climatology_map_sose import \ + ClimatologyMapSoseTemperature, ClimatologyMapSoseSalinity +from mpas_analysis.ocean.climatology_map_argo import \ + ClimatologyMapArgoTemperature, ClimatologyMapArgoSalinity -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..e9408dcdf 100644 --- a/mpas_analysis/ocean/climatology_map_antarctic_melt.py +++ b/mpas_analysis/ocean/climatology_map_antarctic_melt.py @@ -1,33 +1,41 @@ +# 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 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): # {{{ """ An analysis task for comparison of Antarctic melt rates against observations - - Authors - ------- - Xylar Asay-Davis """ + # Authors + # ------- + # Xylar Asay-Davis + def __init__(self, config, mpasClimatologyTask, refConfig=None): # {{{ """ @@ -43,11 +51,11 @@ def __init__(self, config, mpasClimatologyTask, refConfig : ``MpasAnalysisConfigParser``, optional Configuration options for a reference run (if any) - - Authors - ------- - Xylar Asay-Davis """ + # Authors + # ------- + # Xylar Asay-Davis + fieldName = 'meltRate' # call the constructor from the base class (AnalysisTask) super(ClimatologyMapAntarcticMelt, self).__init__( @@ -147,11 +155,10 @@ def __init__(self, config, mpasClimatologyTask, def setup_and_check(self): # {{{ """ Perform steps to set up the analysis and check for errors in the setup. - - Authors - ------- - Xylar Asay-Davis """ + # Authors + # ------- + # Xylar Asay-Davis # first, call setup_and_check from the base class # (AnalysisTask), which will perform some common setup @@ -177,11 +184,10 @@ class RemapMpasAntarcticMeltClimatology(RemapMpasClimatologySubtask): # {{{ landIceMask : xarray.DataArray A mask indicating where there is land ice on the ocean grid (thus, where melt rates are valid) - - Authors - ------- - Xylar Asay-Davis """ + # Authors + # ------- + # Xylar Asay-Davis def run_task(self): # {{{ """ @@ -190,11 +196,10 @@ def run_task(self): # {{{ This function has been overridden to load ``landIceMask`` from a restart file for later use in masking the melt rate. It then simply calls the run function from - - Authors - ------- - Xylar Asay-Davis """ + # Authors + # ------- + # Xylar Asay-Davis # first, load the land-ice mask from the restart file dsLandIceMask = xr.open_dataset(self.restartFileName) @@ -222,11 +227,10 @@ def customize_masked_climatology(self, climatology): # {{{ ------- climatology : ``xarray.Dataset`` object the modified climatology data set - - Authors - ------- - Xylar Asay-Davis """ + # Authors + # ------- + # Xylar Asay-Davis fieldName = self.variableList[0] @@ -244,11 +248,10 @@ class RemapObservedAntarcticMeltClimatology(RemapObservedClimatologySubtask): # {{{ """ A subtask for reading and remapping Antarctic melt-rate observations - - Authors - ------- - Xylar Asay-Davis """ + # Authors + # ------- + # Xylar Asay-Davis def get_observation_descriptor(self, fileName): # {{{ ''' @@ -263,11 +266,10 @@ def get_observation_descriptor(self, fileName): # {{{ ------- obsDescriptor : ``MeshDescriptor`` The descriptor for the observation grid - - Authors - ------- - Xylar Asay-Davis ''' + # Authors + # ------- + # Xylar Asay-Davis # create a descriptor of the observation grid using the x/y polar # stereographic coordinates @@ -290,11 +292,10 @@ def build_observational_dataset(self, fileName): # {{{ ------- dsObs : ``xarray.Dataset`` The observational dataset - - Authors - ------- - Xylar Asay-Davis ''' + # Authors + # ------- + # Xylar Asay-Davis # Load MLD observational data dsObs = xr.open_dataset(fileName) diff --git a/mpas_analysis/ocean/climatology_map_argo.py b/mpas_analysis/ocean/climatology_map_argo.py new file mode 100644 index 000000000..5dc2271f8 --- /dev/null +++ b/mpas_analysis/ocean/climatology_map_argo.py @@ -0,0 +1,459 @@ +# 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 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 + +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 = 'temperatureArgo' + # 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='{}Argo'.format(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='Model temperature compared with Argo ' + 'observations', + galleryGroup='Argo Temperature', + groupSubtitle=None, + groupLink='tempArgo', + 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 = 'salinityArgo' + # 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='{}Argo'.format(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='Model Salinity compared with Argo ' + 'observations', + galleryGroup='Argo Salinity', + groupSubtitle=None, + groupLink='salinArgo', + 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'} + 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')) + 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/mpas_analysis/ocean/climatology_map_mld.py b/mpas_analysis/ocean/climatology_map_mld.py index 174f065a6..bdd3148ad 100644 --- a/mpas_analysis/ocean/climatology_map_mld.py +++ b/mpas_analysis/ocean/climatology_map_mld.py @@ -1,32 +1,40 @@ +# 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 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): # {{{ """ An analysis task for comparison of mixed layer depth (mld) against observations - - Authors - ------- - Luke Van Roekel, Xylar Asay-Davis, Milena Veneziani """ + # Authors + # ------- + # Luke Van Roekel, Xylar Asay-Davis, Milena Veneziani + def __init__(self, config, mpasClimatologyTask, refConfig=None): # {{{ """ @@ -42,11 +50,11 @@ def __init__(self, config, mpasClimatologyTask, refConfig : ``MpasAnalysisConfigParser``, optional Configuration options for a reference run (if any) - - Authors - ------- - Xylar Asay-Davis """ + # Authors + # ------- + # Xylar Asay-Davis + fieldName = 'mld' # call the constructor from the base class (AnalysisTask) super(ClimatologyMapMLD, self).__init__( @@ -141,17 +149,39 @@ def __init__(self, config, mpasClimatologyTask, self.add_subtask(subtask) # }}} + + def setup_and_check(self): # {{{ + ''' + Check if MLD capability was turned on in the run. + + Authors + ------- + Xylar Asay-Davis + ''' + + # first, call setup_and_check from the base class (AnalysisTask), + # which will perform some common setup, including storing: + # self.runDirectory , self.historyDirectory, self.plotsDirectory, + # self.namelist, self.runStreams, self.historyStreams, + # self.calendar + super(ClimatologyMapMLD, self).setup_and_check() + + self.check_analysis_enabled( + analysisOptionName='config_am_mixedlayerdepths_enable', + raiseException=True) + + # }}} + # }}} class RemapObservedMLDClimatology(RemapObservedClimatologySubtask): # {{{ """ A subtask for reading and remapping MLD observations - - Authors - ------- - Luke Van Roekel, Xylar Asay-Davis, Milena Veneziani """ + # Authors + # ------- + # Luke Van Roekel, Xylar Asay-Davis, Milena Veneziani def get_observation_descriptor(self, fileName): # {{{ ''' @@ -166,11 +196,10 @@ def get_observation_descriptor(self, fileName): # {{{ ------- obsDescriptor : ``MeshDescriptor`` The descriptor for the observation grid - - Authors - ------- - Xylar Asay-Davis ''' + # Authors + # ------- + # Xylar Asay-Davis # Load MLD observational data dsObs = self.build_observational_dataset(fileName) @@ -197,11 +226,10 @@ def build_observational_dataset(self, fileName): # {{{ ------- dsObs : ``xarray.Dataset`` The observational dataset - - Authors - ------- - Xylar Asay-Davis ''' + # Authors + # ------- + # Xylar Asay-Davis # Load MLD observational data dsObs = xr.open_dataset(fileName) diff --git a/mpas_analysis/ocean/climatology_map_sose.py b/mpas_analysis/ocean/climatology_map_sose.py index 894b8ebd6..3c9cb2ee4 100644 --- a/mpas_analysis/ocean/climatology_map_sose.py +++ b/mpas_analysis/ocean/climatology_map_sose.py @@ -1,39 +1,46 @@ +# 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. - -Authors -------- -Xylar Asay-Davis ''' +# Authors +# ------- +# Xylar Asay-Davis 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): # {{{ """ An analysis task for comparison of antarctic temperature against SOSE fields - - Authors - ------- - Xylar Asay-Davis """ + # Authors + # ------- + # Xylar Asay-Davis def __init__(self, config, mpasClimatologyTask, refConfig=None): # {{{ @@ -50,12 +57,12 @@ def __init__(self, config, mpasClimatologyTask, refConfig : ``MpasAnalysisConfigParser``, optional Configuration options for a reference run (if any) - - Authors - ------- - Xylar Asay-Davis """ - fieldName = 'temperature' + # Authors + # ------- + # Xylar Asay-Davis + + fieldName = 'temperatureSOSE' # call the constructor from the base class (AnalysisTask) super(ClimatologyMapSoseTemperature, self).__init__( config=config, taskName='climatologyMapSoseTemperature', @@ -117,7 +124,7 @@ def __init__(self, config, mpasClimatologyTask, remapObservationsSubtask = RemapSoseClimatology( parentTask=self, seasons=seasons, fileName=obsFileName, - outFilePrefix=refFieldName, + outFilePrefix='{}SOSE'.format(refFieldName), fieldName=refFieldName, botFieldName='botTheta', depths=depths, @@ -155,10 +162,10 @@ 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', + groupLink='tempSose', galleryName=galleryName) self.add_subtask(subtask) @@ -171,11 +178,10 @@ class ClimatologyMapSoseSalinity(AnalysisTask): # {{{ """ An analysis task for comparison of antarctic salinity against SOSE fields - - Authors - ------- - Xylar Asay-Davis """ + # Authors + # ------- + # Xylar Asay-Davis def __init__(self, config, mpasClimatologyTask, refConfig=None): # {{{ @@ -192,12 +198,12 @@ def __init__(self, config, mpasClimatologyTask, refConfig : ``MpasAnalysisConfigParser``, optional Configuration options for a reference run (if any) - - Authors - ------- - Xylar Asay-Davis """ - fieldName = 'salinity' + # Authors + # ------- + # Xylar Asay-Davis + + fieldName = 'salinitySOSE' # call the constructor from the base class (AnalysisTask) super(ClimatologyMapSoseSalinity, self).__init__( config=config, taskName='climatologyMapSoseSalinity', @@ -259,7 +265,7 @@ def __init__(self, config, mpasClimatologyTask, remapObservationsSubtask = RemapSoseClimatology( parentTask=self, seasons=seasons, fileName=obsFileName, - outFilePrefix=refFieldName, + outFilePrefix='{}SOSE'.format(refFieldName), fieldName=refFieldName, botFieldName='botSalinity', depths=depths, @@ -297,10 +303,10 @@ 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', + groupLink='salinSose', galleryName=galleryName) self.add_subtask(subtask) @@ -313,11 +319,10 @@ class RemapSoseClimatology(RemapObservedClimatologySubtask): # {{{ """ A subtask for reading and remapping SOSE fields to the comparison grid - - Authors - ------- - Xylar Asay-Davis """ + # Authors + # ------- + # Xylar Asay-Davis def __init__(self, parentTask, seasons, fileName, outFilePrefix, fieldName, botFieldName, depths, @@ -360,12 +365,10 @@ def __init__(self, parentTask, seasons, fileName, outFilePrefix, subtaskName : str, optional The name of the subtask - - Authors - ------- - Xylar Asay-Davis - ''' + # Authors + # ------- + # Xylar Asay-Davis self.fieldName = fieldName self.botFieldName = botFieldName @@ -391,11 +394,10 @@ def get_observation_descriptor(self, fileName): # {{{ ------- obsDescriptor : ``MeshDescriptor`` The descriptor for the observation grid - - Authors - ------- - Xylar Asay-Davis ''' + # Authors + # ------- + # Xylar Asay-Davis # create a descriptor of the observation grid using the x/y polar # stereographic coordinates @@ -418,11 +420,10 @@ def build_observational_dataset(self, fileName): # {{{ ------- dsObs : ``xarray.Dataset`` The observational dataset - - Authors - ------- - Xylar Asay-Davis ''' + # Authors + # ------- + # Xylar Asay-Davis # Load MLD observational data dsObs = xr.open_dataset(fileName) diff --git a/mpas_analysis/ocean/climatology_map_ssh.py b/mpas_analysis/ocean/climatology_map_ssh.py new file mode 100644 index 000000000..f7772b6cd --- /dev/null +++ b/mpas_analysis/ocean/climatology_map_ssh.py @@ -0,0 +1,256 @@ +# 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 + +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 + +from mpas_analysis.shared.constants import constants + + +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_pressureAdjustedSSH' + + 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 = RemapSSHClimatology( + mpasClimatologyTask=mpasClimatologyTask, + parentTask=self, + climatologyName=fieldName, + variableList=[mpasFieldName], + comparisonGridNames=comparisonGridNames, + seasons=seasons, + iselValues=iselValues) + + if refConfig is None: + + refTitleLabel = 'Observations (AVISO Dynamic ' \ + 'Topography, 1993-2010)' + + 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, removeMean=True) + + subtask.set_plot_info( + outFileLabel=outFileLabel, + fieldNameInTitle='Zero-mean SSH', + mpasFieldName=mpasFieldName, + refFieldName=refFieldName, + refTitleLabel=refTitleLabel, + diffTitleLabel=diffTitleLabel, + unitsLabel=r'cm', + imageCaption='Mean Sea Surface Height', + galleryGroup='Sea Surface Height', + groupSubtitle=None, + groupLink='ssh', + galleryName=galleryName) + + self.add_subtask(subtask) + # }}} + # }}} + + +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 + """ + # 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'] + + # scale the field to cm from m + dsObs['zos'] = constants.cm_per_m * dsObs['zos'] + + return dsObs # }}} + + # }}} + +# vim: foldmethod=marker ai ts=4 sts=4 et sw=4 ft=python diff --git a/mpas_analysis/ocean/climatology_map_sss.py b/mpas_analysis/ocean/climatology_map_sss.py index 0fdc0877d..30359fc48 100644 --- a/mpas_analysis/ocean/climatology_map_sss.py +++ b/mpas_analysis/ocean/climatology_map_sss.py @@ -1,30 +1,38 @@ +# 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 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): # {{{ """ An analysis task for comparison of sea surface salinity (sss) against observations - - Authors - ------- - Luke Van Roekel, Xylar Asay-Davis, Milena Veneziani """ + # Authors + # ------- + # Luke Van Roekel, Xylar Asay-Davis, Milena Veneziani + def __init__(self, config, mpasClimatologyTask, refConfig=None): # {{{ """ @@ -40,11 +48,11 @@ def __init__(self, config, mpasClimatologyTask, refConfig : ``MpasAnalysisConfigParser``, optional Configuration options for a reference run (if any) - - Authors - ------- - Xylar Asay-Davis """ + # Authors + # ------- + # Xylar Asay-Davis + fieldName = 'sss' # call the constructor from the base class (AnalysisTask) super(ClimatologyMapSSS, self).__init__( @@ -146,11 +154,10 @@ def __init__(self, config, mpasClimatologyTask, class RemapObservedSSSClimatology(RemapObservedClimatologySubtask): # {{{ """ A subtask for reading and remapping SSS observations - - Authors - ------- - Luke Van Roekel, Xylar Asay-Davis, Milena Veneziani """ + # Authors + # ------- + # Luke Van Roekel, Xylar Asay-Davis, Milena Veneziani def get_observation_descriptor(self, fileName): # {{{ ''' @@ -165,11 +172,10 @@ def get_observation_descriptor(self, fileName): # {{{ ------- obsDescriptor : ``MeshDescriptor`` The descriptor for the observation grid - - Authors - ------- - Xylar Asay-Davis ''' + # Authors + # ------- + # Xylar Asay-Davis # create a descriptor of the observation grid using the lat/lon # coordinates @@ -192,11 +198,10 @@ def build_observational_dataset(self, fileName): # {{{ ------- dsObs : ``xarray.Dataset`` The observational dataset - - Authors - ------- - Xylar Asay-Davis ''' + # Authors + # ------- + # Xylar Asay-Davis timeStart = datetime.datetime(2011, 8, 1) timeEnd = datetime.datetime(2014, 12, 31) diff --git a/mpas_analysis/ocean/climatology_map_sst.py b/mpas_analysis/ocean/climatology_map_sst.py index 0a5b1d699..48fb4c109 100644 --- a/mpas_analysis/ocean/climatology_map_sst.py +++ b/mpas_analysis/ocean/climatology_map_sst.py @@ -1,30 +1,38 @@ +# 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 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): # {{{ """ An analysis task for comparison of sea surface temperature (sst) against observations - - Authors - ------- - Luke Van Roekel, Xylar Asay-Davis, Milena Veneziani """ + # Authors + # ------- + # Luke Van Roekel, Xylar Asay-Davis, Milena Veneziani + def __init__(self, config, mpasClimatologyTask, refConfig=None): # {{{ """ @@ -40,11 +48,11 @@ def __init__(self, config, mpasClimatologyTask, refConfig : ``MpasAnalysisConfigParser``, optional Configuration options for a reference run (if any) - - Authors - ------- - Xylar Asay-Davis """ + # Authors + # ------- + # Xylar Asay-Davis + fieldName = 'sst' # call the constructor from the base class (AnalysisTask) super(ClimatologyMapSST, self).__init__( @@ -156,11 +164,10 @@ def __init__(self, config, mpasClimatologyTask, class RemapObservedSSTClimatology(RemapObservedClimatologySubtask): # {{{ """ A subtask for reading and remapping SST observations - - Authors - ------- - Luke Van Roekel, Xylar Asay-Davis, Milena Veneziani """ + # Authors + # ------- + # Luke Van Roekel, Xylar Asay-Davis, Milena Veneziani def get_observation_descriptor(self, fileName): # {{{ ''' @@ -175,11 +182,10 @@ def get_observation_descriptor(self, fileName): # {{{ ------- obsDescriptor : ``MeshDescriptor`` The descriptor for the observation grid - - Authors - ------- - Xylar Asay-Davis ''' + # Authors + # ------- + # Xylar Asay-Davis # create a descriptor of the observation grid using the lat/lon # coordinates @@ -202,11 +208,10 @@ def build_observational_dataset(self, fileName): # {{{ ------- dsObs : ``xarray.Dataset`` The observational dataset - - Authors - ------- - Xylar Asay-Davis ''' + # Authors + # ------- + # Xylar Asay-Davis climStartYear = self.config.getint('oceanObservations', 'sstClimatologyStartYear') diff --git a/mpas_analysis/ocean/compute_anomaly_subtask.py b/mpas_analysis/ocean/compute_anomaly_subtask.py index befefbf8c..cac91ea65 100644 --- a/mpas_analysis/ocean/compute_anomaly_subtask.py +++ b/mpas_analysis/ocean/compute_anomaly_subtask.py @@ -1,19 +1,28 @@ # -*- coding: utf-8 -*- +# +# 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 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): @@ -43,11 +52,10 @@ class ComputeAnomalySubtask(AnalysisTask): variable computed from others). This operation is performed before computing moving averages and anomalies, so that these operations are also performed on any new variables added to the data set. - - Authors - ------- - Xylar Asay-Davis """ + # Authors + # ------- + # Xylar Asay-Davis def __init__(self, parentTask, mpasTimeSeriesTask, outFileName, variableList, movingAveragePoints, @@ -83,11 +91,11 @@ def __init__(self, parentTask, mpasTimeSeriesTask, outFileName, variable computed from others). This operation is performed before computing moving averages and anomalies, so that these operations are also performed on any new variables added to the data set. - - Authors - ------- - Xylar Asay-Davis """ + # Authors + # ------- + # Xylar Asay-Davis + # first, call the constructor from the base class (AnalysisTask) super(ComputeAnomalySubtask, self).__init__( config=parentTask.config, @@ -111,11 +119,11 @@ def __init__(self, parentTask, mpasTimeSeriesTask, outFileName, def setup_and_check(self): # {{{ """ Perform steps to set up the analysis and check for errors in the setup. - - Authors - ------- - Xylar Asay-Davis """ + # Authors + # ------- + # Xylar Asay-Davis + # first, call setup_and_check from the base class (AnalysisTask), # which will perform some common setup, including storing: # self.runDirectory , self.historyDirectory, self.plotsDirectory, @@ -132,11 +140,10 @@ def setup_and_check(self): # {{{ def run_task(self): # {{{ """ Performs analysis of ocean heat content (OHC) from time-series output. - - Authors - ------- - Xylar Asay-Davis, Milena Veneziani, Greg Streletz """ + # Authors + # ------- + # Xylar Asay-Davis, Milena Veneziani, Greg Streletz self.logger.info("\nComputing anomalies...") @@ -144,12 +151,20 @@ 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) + anomalyEndDate = '{:04d}-12-31_23:59:59'.format(anomalyYear) + else: + anomalyRefDate = get_simulation_start_time(self.runStreams) + anomalyYear = int(anomalyRefDate[0:4]) + anomalyEndDate = '{:04d}-12-31_23:59:59'.format(anomalyYear) ds = compute_moving_avg_anomaly_from_start( timeSeriesFileName=self.inputFile, variableList=self.variableList, - simulationStartTime=simulationStartTime, + anomalyStartTime=anomalyRefDate, + anomalyEndTime=anomalyEndDate, startDate=startDate, endDate=endDate, calendar=self.calendar, diff --git a/mpas_analysis/ocean/index_nino34.py b/mpas_analysis/ocean/index_nino34.py index 608621328..b54c5d81f 100644 --- a/mpas_analysis/ocean/index_nino34.py +++ b/mpas_analysis/ocean/index_nino34.py @@ -1,4 +1,12 @@ # -*- coding: utf-8 -*- +# +# 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 @@ -10,19 +18,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): # {{{ @@ -38,11 +46,10 @@ class IndexNino34(AnalysisTask): # {{{ refConfig : ``MpasAnalysisConfigParser`` Configuration options for a reference run (if any) - - Authors - ------- - Luke Van Roekel, Xylar Asay-Davis ''' + # Authors + # ------- + # Luke Van Roekel, Xylar Asay-Davis def __init__(self, config, mpasTimeSeriesTask, refConfig=None): # {{{ @@ -59,12 +66,11 @@ def __init__(self, config, mpasTimeSeriesTask, refConfig=None): refConfig : ``MpasAnalysisConfigParser``, optional Configuration options for a reference run (if any) - - Authors - ------- - Xylar Asay-Davis - ''' + # Authors + # ------- + # Xylar Asay-Davis + # first, call the constructor from the base class (AnalysisTask) super(IndexNino34, self).__init__( config=config, @@ -82,11 +88,10 @@ def __init__(self, config, mpasTimeSeriesTask, refConfig=None): def setup_and_check(self): # {{{ ''' Perform steps to set up the analysis and check for errors in the setup. - - Authors - ------- - Xylar Asay-Davis ''' + # Authors + # ------- + # Xylar Asay-Davis # first, call setup_and_check from the base class (AnalysisTask), # which will perform some common setup, including storing: @@ -115,11 +120,10 @@ def run_task(self): # {{{ ''' Computes NINO34 index and plots the time series and power spectrum with 95 and 99% confidence bounds - - Authors - ------- - Luke Van Roekel, Xylar Asay-Davis ''' + # Authors + # ------- + # Luke Van Roekel, Xylar Asay-Davis self.logger.info("\nPlotting Nino3.4 time series and power " "spectrum....") @@ -292,11 +296,10 @@ def _compute_nino34_index(self, regionSST, calendar): # {{{ Returns ------- xarray.DataArray object containing the nino34index - - Authors - ------- - Luke Van Roekel, Xylar Asay-Davis """ + # Authors + # ------- + # Luke Van Roekel, Xylar Asay-Davis if not isinstance(regionSST, xr.core.dataarray.DataArray): raise ValueError('regionSST should be an xarray DataArray') @@ -352,11 +355,10 @@ def _compute_nino34_spectra(self, nino34Index): # {{{ mkov*scale*xHigh : numpy.array 99% confidence threshold from chi-squared test - - Authors - ------- - Luke Van Roekel, Xylar Asay-Davis """ + # Authors + # ------- + # Luke Van Roekel, Xylar Asay-Davis # Move nino34Index to numpy to allow functionality with scipy routines ninoIndex = nino34Index.values @@ -419,11 +421,10 @@ def _autocorr(self, x, t=1): # {{{ ------- Single value giving the lag one auto-correlation If t != 1, this is no longer a lag one auto-correlation - - Authors - ------- - Luke Van Roekel """ + # Authors + # ------- + # Luke Van Roekel return np.corrcoef(np.array([x[0:len(x)-t], x[t:len(x)]])) # }}} @@ -441,11 +442,10 @@ def _running_mean(self, inputData, wgts): # {{{ for the nino index this is a 5-point boxcar window for the nino power spectra this is a modified Daniell window (see https://www.ncl.ucar.edu/Document/Functions/Built-in/specx_anal.shtml) - - Authors - ------- - Luke Van Roekel, Xylar Asay-Davis """ + # Authors + # ------- + # Luke Van Roekel, Xylar Asay-Davis nt = len(inputData) sp = (len(wgts) - 1) // 2 @@ -500,11 +500,11 @@ def _nino34_spectra_plot(self, spectra, title, panelTitles, periodMin, periodMax : float, optional the maximum and minimum periods (in years) to be plotted - - Authors - ------- - Luke Van Roekel, Xylar Asay-Davis """ + # Authors + # ------- + # Luke Van Roekel, Xylar Asay-Davis + config = self.config if dpi is None: @@ -602,11 +602,11 @@ def _nino34_timeseries_plot(self, nino34s, title, panelTitles, outFileName, lineWidth : int, optional control line width - - Authors - ------- - Luke Van Roekel, Xylar Asay-Davis """ + # Authors + # ------- + # Luke Van Roekel, Xylar Asay-Davis + config = self.config calendar = self.calendar @@ -635,7 +635,7 @@ def _nino34_timeseries_plot(self, nino34s, title, panelTitles, outFileName, minDays = time.min() maxDays = time.max() - plot_xtick_format(plt, calendar, minDays, maxDays, maxXTicks) + plot_xtick_format(calendar, minDays, maxDays, maxXTicks) plt.tight_layout(rect=[0, 0.03, 1, 0.90]) @@ -672,11 +672,11 @@ def _plot_nino_timeseries(self, ninoIndex, time, xlabel, ylabel, lineWidth : list of str control line width - - Authors - ------- - Luke Van Roekel, Xylar Asay-Davis ''' + # Authors + # ------- + # Luke Van Roekel, Xylar Asay-Davis + plt.title(panelTitle, y=1.06, **title_font) y1 = ninoIndex nt = np.size(ninoIndex) @@ -728,11 +728,11 @@ def _plot_size_y_axis(self, x, ys, xmin, xmax): xmax : float, optional The maximum x values - - Authors - ------- - Luke Van Roekel, Xylar Asay-Davis ''' + # Authors + # ------- + # Luke Van Roekel, Xylar Asay-Davis + mask = np.logical_and(x >= xmin, x <= xmax) # find maximum value of three curves plotted diff --git a/mpas_analysis/ocean/meridional_heat_transport.py b/mpas_analysis/ocean/meridional_heat_transport.py index e6b139e76..5dee1e3f8 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 @@ -6,16 +13,14 @@ import numpy as np import os -from ..shared.plot.plotting import plot_vertical_section,\ - setup_colormap, plot_1D +from mpas_analysis.shared.plot.plotting import plot_vertical_section, 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 ..shared.climatology import get_unmasked_mpas_climatology_file_name +from mpas_analysis.shared import AnalysisTask +from mpas_analysis.shared.html import write_image_xml class MeridionalHeatTransport(AnalysisTask): # {{{ @@ -30,11 +35,10 @@ class MeridionalHeatTransport(AnalysisTask): # {{{ refConfig : ``MpasAnalysisConfigParser`` Configuration options for a reference run (if any) - - Authors - ------- - Mark Petersen, Milena Veneziani, Xylar Asay-Davis ''' + # Authors + # ------- + # Mark Petersen, Milena Veneziani, Xylar Asay-Davis def __init__(self, config, mpasClimatologyTask, refConfig=None): # {{{ ''' @@ -50,12 +54,11 @@ def __init__(self, config, mpasClimatologyTask, refConfig=None): # {{{ refConfig : ``MpasAnalysisConfigParser``, optional Configuration options for a reference run (if any) - - Authors - ------- - Xylar Asay-Davis - ''' + # Authors + # ------- + # Xylar Asay-Davis + # first, call the constructor from the base class (AnalysisTask) super(MeridionalHeatTransport, self).__init__( config=config, @@ -73,11 +76,10 @@ def __init__(self, config, mpasClimatologyTask, refConfig=None): # {{{ def setup_and_check(self): # {{{ ''' Perform steps to set up the analysis and check for errors in the setup. - - Authors - ------- - Mark Petersen, Milena Veneziani, Xylar Asay-Davis ''' + # Authors + # ------- + # Mark Petersen, Milena Veneziani, Xylar Asay-Davis # first, call setup_and_check from the base class (AnalysisTask), # which will perform some common setup, including storing: @@ -146,11 +148,11 @@ def run_task(self): # {{{ Plots MHT as: 1D function of latitude 2D function of latitude and depth - - Authors - ------- - Mark Petersen, Milena Veneziani, Xylar Asay-Davis """ + # Authors + # ------- + # Mark Petersen, Milena Veneziani, Xylar Asay-Davis + self.logger.info("\nPlotting meridional heat transport (MHT)...") config = self.config @@ -172,7 +174,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) @@ -340,18 +341,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 826046a0f..b1086302a 100644 --- a/mpas_analysis/ocean/plot_climatology_map_subtask.py +++ b/mpas_analysis/ocean/plot_climatology_map_subtask.py @@ -1,11 +1,17 @@ +# 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. - -Authors -------- -Luke Van Roekel, Xylar Asay-Davis, Milena Veneziani """ +# Authors +# ------- +# Luke Van Roekel, Xylar Asay-Davis, Milena Veneziani from __future__ import absolute_import, division, print_function, \ unicode_literals @@ -13,16 +19,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, \ - setup_colormap, plot_polar_projection_comparison +from mpas_analysis.shared.plot.plotting import plot_global_comparison, \ + 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): @@ -56,6 +63,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 @@ -97,15 +111,14 @@ class PlotClimatologyMapSubtask(AnalysisTask): # {{{ depth : {None, float, 'top', 'bot'} Depth at which to perform the comparison, 'top' for the sea surface 'bot' for the sea floor - - Authors - ------- - Luke Van Roekel, Xylar Asay-Davis, Milena Veneziani """ + # Authors + # ------- + # Luke Van Roekel, Xylar Asay-Davis, Milena Veneziani 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 @@ -138,11 +151,16 @@ def __init__(self, parentTask, season, comparisonGridName, Depth the data is being plotted, 'top' for the sea surface 'bot' for the sea floor - Authors - ------- - Xylar Asay-Davis - + 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 self.season = season self.depth = depth @@ -150,6 +168,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: @@ -222,11 +241,11 @@ def set_plot_info(self, outFileLabel, fieldNameInTitle, mpasFieldName, diffTitleLabel : str, optional the title of the difference subplot - - Authors - ------- - Xylar Asay-Davis """ + # Authors + # ------- + # Xylar Asay-Davis + self.outFileLabel = outFileLabel self.fieldNameInTitle = fieldNameInTitle self.mpasFieldName = mpasFieldName @@ -262,11 +281,11 @@ def set_plot_info(self, outFileLabel, fieldNameInTitle, mpasFieldName, def setup_and_check(self): # {{{ """ Perform steps to set up the analysis and check for errors in the setup. - - Authors - ------- - Xylar Asay-Davis """ + # Authors + # ------- + # Xylar Asay-Davis + # first, call setup_and_check from the base class (AnalysisTask), # which will perform some common setup, including storing: # self.runDirectory , self.historyDirectory, self.plotsDirectory, @@ -303,11 +322,10 @@ def run_task(self): # {{{ """ Plots a comparison of ACME/MPAS output to SST, MLD or SSS observations or a reference run - - Authors - ------- - Luke Van Roekel, Xylar Asay-Davis, Milena Veneziani """ + # Authors + # ------- + # Luke Van Roekel, Xylar Asay-Davis, Milena Veneziani season = self.season depth = self.depth @@ -368,6 +386,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': @@ -385,11 +421,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) @@ -418,10 +449,7 @@ def _plot_latlon(self, remappedModelClimatology, remappedRefClimatology): modelOutput, refOutput, bias, - colormapResult, - colorbarLevelsResult, - colormapDifference, - colorbarLevelsDifference, + configSectionName, fileout=outFileName, title=title, modelTitle='{}'.format(mainRunName), @@ -482,15 +510,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, @@ -501,7 +520,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_depth_integrated_time_series_subtask.py b/mpas_analysis/ocean/plot_depth_integrated_time_series_subtask.py index 10f3b1bf2..b070f5336 100644 --- a/mpas_analysis/ocean/plot_depth_integrated_time_series_subtask.py +++ b/mpas_analysis/ocean/plot_depth_integrated_time_series_subtask.py @@ -1,25 +1,34 @@ # -*- coding: utf-8 -*- +# +# 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 -import xarray as xr import os +import xarray -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, write_netcdf -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): @@ -74,11 +83,10 @@ class PlotDepthIntegratedTimeSeriesSubtask(AnalysisTask): refConfig : ``MpasAnalysisConfigParser`` The configuration options for the reference run (if any) - - Authors - ------- - Xylar Asay-Davis, Milena Veneziani, Greg Streletz """ + # Authors + # ------- + # Xylar Asay-Davis, Milena Veneziani, Greg Streletz def __init__(self, parentTask, regionName, inFileName, outFileLabel, fieldNameInTitle, mpasFieldName, yAxisLabel, sectionName, @@ -141,11 +149,10 @@ def __init__(self, parentTask, regionName, inFileName, outFileLabel, refConfig : ``MpasAnalysisConfigParser``, optional The configuration options for the reference run (if any) - - Authors - ------- - Xylar Asay-Davis """ + # Authors + # ------- + # Xylar Asay-Davis if subtaskName is None: suffix = regionName[0].upper() + regionName[1:] @@ -182,11 +189,11 @@ def __init__(self, parentTask, regionName, inFileName, outFileLabel, def setup_and_check(self): # {{{ """ Perform steps to set up the analysis and check for errors in the setup. - - Authors - ------- - Xylar Asay-Davis, Greg Streletz """ + # Authors + # ------- + # Xylar Asay-Davis, Greg Streletz + # first, call setup_and_check from the base class (AnalysisTask), # which will perform some common setup, including storing: # self.runDirectory , self.historyDirectory, self.plotsDirectory, @@ -207,6 +214,18 @@ def setup_and_check(self): # {{{ self.refFileName = '{}/{}'.format(baseDirectory, self.inFileName) + preprocessedReferenceRunName = config.get( + 'runs', 'preprocessedReferenceRunName') + if preprocessedReferenceRunName != 'None': + + assert(not os.path.isabs(self.inFileName)) + + baseDirectory = build_config_full_path( + config, 'output', 'timeSeriesSubdirectory') + + self.preprocessedFileName = '{}/preprocessed_{}'.format( + baseDirectory, self.inFileName) + if not os.path.isabs(self.inFileName): baseDirectory = build_config_full_path( config, 'output', 'timeSeriesSubdirectory') @@ -227,11 +246,10 @@ def setup_and_check(self): # {{{ def run_task(self): # {{{ """ Compute vertical agregates of the data and plot the time series - - Authors - ------- - Xylar Asay-Davis, Milena Veneziani, Greg Streletz """ + # Authors + # ------- + # Xylar Asay-Davis, Milena Veneziani, Greg Streletz self.logger.info("\nPlotting depth-integrated time series of " "{}...".format(self.fieldNameInTitle)) @@ -345,6 +363,13 @@ def run_task(self): # {{{ 'not be plotted.') preprocessedReferenceRunName = 'None' + # rolling mean seems to have trouble with dask data sets so we + # write out the data set and read it back as a single-file data set + # (without dask) + dsPreprocessed = dsPreprocessed.drop('xtime') + write_netcdf(dsPreprocessed, self.preprocessedFileName) + dsPreprocessed = xarray.open_dataset(self.preprocessedFileName) + if preprocessedReferenceRunName != 'None': color = 'r' title = '{} \n {} (red)'.format(title, @@ -360,13 +385,13 @@ def run_task(self): # {{{ divisionDepths] + ['btm'] # these preprocessed data are OHC *anomalies* + dsPreprocessed = compute_moving_avg(dsPreprocessed, + movingAveragePoints) for rangeIndex in range(len(suffixes)): variableName = '{}_{}'.format(preprocessedFieldPrefix, suffixes[rangeIndex]) if variableName in list(dsPreprocessed.data_vars.keys()): - field = dsPreprocessed[variableName] - field = compute_moving_avg(field, movingAveragePoints) - timeSeries.append(field) + timeSeries.append(dsPreprocessed[variableName]) else: self.logger.warning('Warning: Preprocessed variable {} ' 'not found. Skipping.'.format( @@ -412,11 +437,25 @@ def run_task(self): # {{{ maxPoints.append(points[rangeIndex]) legendText.append(None) + if config.has_option(self.taskName, 'firstYearXTicks'): + firstYearXTicks = config.getint(self.taskName, + 'firstYearXTicks') + else: + firstYearXTicks = None + + if config.has_option(self.taskName, 'yearStrideXTicks'): + yearStrideXTicks = config.getint(self.taskName, + 'yearStrideXTicks') + else: + yearStrideXTicks = None + timeseries_analysis_plot(config=config, dsvalues=timeSeries, N=None, title=title, xlabel=xLabel, ylabel=yLabel, fileout=figureName, lineStyles=lineStyles, lineWidths=lineWidths, maxPoints=maxPoints, - legendText=legendText, calendar=calendar) + legendText=legendText, calendar=calendar, + firstYearXTicks=firstYearXTicks, + yearStrideXTicks=yearStrideXTicks) write_image_xml( config=config, diff --git a/mpas_analysis/ocean/plot_hovmoller_subtask.py b/mpas_analysis/ocean/plot_hovmoller_subtask.py index 2c802c8d7..3fe7d927a 100644 --- a/mpas_analysis/ocean/plot_hovmoller_subtask.py +++ b/mpas_analysis/ocean/plot_hovmoller_subtask.py @@ -1,4 +1,12 @@ # -*- coding: utf-8 -*- +# +# 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 @@ -6,15 +14,15 @@ 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 -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): @@ -67,11 +75,10 @@ class PlotHovmollerSubtask(AnalysisTask): galleryName : str The name of the gallery in which this plot belongs - - Authors - ------- - Xylar Asay-Davis, Milena Veneziani, Greg Streletz """ + # Authors + # ------- + # Xylar Asay-Davis, Milena Veneziani, Greg Streletz def __init__(self, parentTask, regionName, inFileName, outFileLabel, fieldNameInTitle, mpasFieldName, unitsLabel, sectionName, @@ -130,11 +137,10 @@ def __init__(self, parentTask, regionName, inFileName, outFileLabel, subtaskName : str The name of the subtask (``plotHovmoller`` by default) - - Authors - ------- - Xylar Asay-Davis """ + # Authors + # ------- + # Xylar Asay-Davis if subtaskName is None: suffix = regionName[0].upper() + regionName[1:] @@ -169,11 +175,11 @@ def __init__(self, parentTask, regionName, inFileName, outFileLabel, def setup_and_check(self): # {{{ """ Perform steps to set up the analysis and check for errors in the setup. - - Authors - ------- - Xylar Asay-Davis, Greg Streletz """ + # Authors + # ------- + # Xylar Asay-Davis, Greg Streletz + # first, call setup_and_check from the base class (AnalysisTask), # which will perform some common setup, including storing: # self.runDirectory , self.historyDirectory, self.plotsDirectory, @@ -203,11 +209,10 @@ def setup_and_check(self): # {{{ def run_task(self): # {{{ """ Make the Hovmoller plot from the time series. - - Authors - ------- - Xylar Asay-Davis, Milena Veneziani, Greg Streletz """ + # Authors + # ------- + # Xylar Asay-Davis, Milena Veneziani, Greg Streletz self.logger.info("\nPlotting {} trends vs. depth...".format( self.fieldNameInTitle)) @@ -259,18 +264,25 @@ 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) + if config.has_option(self.sectionName, 'firstYearXTicks'): + firstYearXTicks = config.getint(self.sectionName, + 'firstYearXTicks') + else: + firstYearXTicks = None + + if config.has_option(self.sectionName, 'yearStrideXTicks'): + yearStrideXTicks = config.getint(self.sectionName, + 'yearStrideXTicks') + else: + yearStrideXTicks = None + + 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, + firstYearXTicks=firstYearXTicks, + yearStrideXTicks=yearStrideXTicks) write_image_xml( config=config, diff --git a/mpas_analysis/ocean/remap_depth_slices_subtask.py b/mpas_analysis/ocean/remap_depth_slices_subtask.py index 6788fe43e..d8626ee2f 100644 --- a/mpas_analysis/ocean/remap_depth_slices_subtask.py +++ b/mpas_analysis/ocean/remap_depth_slices_subtask.py @@ -1,14 +1,21 @@ +# 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 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): # {{{ @@ -27,11 +34,10 @@ class RemapDepthSlicesSubtask(RemapMpasClimatologySubtask): # {{{ verticalIndices : xarray.DataArray The vertical indices of slice to be plotted - - Authors - ------- - Xylar Asay-Davis """ + # Authors + # ------- + # Xylar Asay-Davis def __init__(self, mpasClimatologyTask, parentTask, climatologyName, variableList, seasons, depths, comparisonGridNames=['latlon'], @@ -74,11 +80,10 @@ def __init__(self, mpasClimatologyTask, parentTask, climatologyName, iselValues : dict, optional A dictionary of dimensions and indices (or ``None``) used to extract a slice of the MPAS field(s). - - Authors - ------- - Xylar Asay-Davis ''' + # Authors + # ------- + # Xylar Asay-Davis self.depths = depths @@ -86,7 +91,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): # {{{ """ @@ -97,11 +102,10 @@ def run_task(self): # {{{ ``verticalIndex`` is also computed for later indexing of the model level. It then simply calls the run function from ClimatologyMapOcean. - - Authors - ------- - Xylar Asay-Davis """ + # Authors + # ------- + # Xylar Asay-Davis # first, load the land-ice mask from the restart file ds = xr.open_dataset(self.restartFileName) @@ -183,11 +187,10 @@ def customize_masked_climatology(self, climatology): # {{{ ------- climatology : ``xarray.Dataset`` object the modified climatology data set - - Authors - ------- - Xylar Asay-Davis """ + # Authors + # ------- + # Xylar Asay-Davis if self.depths is None: return climatology diff --git a/mpas_analysis/ocean/streamfunction_moc.py b/mpas_analysis/ocean/streamfunction_moc.py index 974b32845..0753da5b2 100644 --- a/mpas_analysis/ocean/streamfunction_moc.py +++ b/mpas_analysis/ocean/streamfunction_moc.py @@ -1,4 +1,12 @@ # -*- coding: utf-8 -*- +# +# 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 @@ -8,19 +16,20 @@ import netCDF4 import os -from ..shared.constants.constants import m3ps_to_Sv -from ..shared.plot.plotting import plot_vertical_section,\ - timeseries_analysis_plot, setup_colormap +from mpas_analysis.shared.constants.constants import m3ps_to_Sv +from mpas_analysis.shared.plot.plotting import plot_vertical_section,\ + timeseries_analysis_plot -from ..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 ..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): # {{{ @@ -38,11 +47,10 @@ class StreamfunctionMOC(AnalysisTask): # {{{ mpasClimatologyTask : ``MpasClimatologyTask`` The task that produced the climatology to be remapped and plotted - - Authors - ------- - Milena Veneziani, Mark Petersen, Phillip Wolfram, Xylar Asay-Davis ''' + # Authors + # ------- + # Milena Veneziani, Mark Petersen, Phillip Wolfram, Xylar Asay-Davis def __init__(self, config, mpasClimatologyTask): # {{{ ''' @@ -55,12 +63,11 @@ def __init__(self, config, mpasClimatologyTask): # {{{ mpasClimatologyTask : ``MpasClimatologyTask`` The task that produced the climatology to be remapped and plotted - - Authors - ------- - Xylar Asay-Davis - ''' + # Authors + # ------- + # Xylar Asay-Davis + # first, call the constructor from the base class (AnalysisTask) super(StreamfunctionMOC, self).__init__( config=config, @@ -80,11 +87,10 @@ def setup_and_check(self): # {{{ ------ ValueError if timeSeriesStatsMonthly is not enabled in the MPAS run - - Authors - ------- - Xylar Asay-Davis ''' + # Authors + # ------- + # Xylar Asay-Davis # first, call setup_and_check from the base class (AnalysisTask), # which will perform some common setup, including storing: @@ -111,8 +117,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']) @@ -147,11 +162,10 @@ def run_task(self): # {{{ post-processing if not. Plots streamfunction climatolgoical sections as well as time series of max Atlantic MOC at 26.5N (latitude of RAPID MOC Array). - - Authors - ------- - Milena Veneziani, Mark Petersen, Phillip J. Wolfram, Xylar Asay-Davis ''' + # Authors + # ------- + # Milena Veneziani, Mark Petersen, Phillip J. Wolfram, Xylar Asay-Davis self.logger.info("\nPlotting streamfunction of Meridional Overturning " "Circulation (MOC)...") @@ -196,20 +210,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) @@ -233,11 +241,25 @@ def run_task(self): # {{{ figureName = '{}/{}.png'.format(self.plotsDirectory, filePrefix) + if config.has_option(self.taskName, 'firstYearXTicks'): + firstYearXTicks = config.getint(self.taskName, + 'firstYearXTicks') + else: + firstYearXTicks = None + + if config.has_option(self.taskName, 'yearStrideXTicks'): + yearStrideXTicks = config.getint(self.taskName, + 'yearStrideXTicks') + else: + yearStrideXTicks = None + timeseries_analysis_plot(config, [dsMOCTimeSeries.mocAtlantic26], movingAveragePoints, title, xLabel, yLabel, figureName, lineStyles=['k-'], lineWidths=[2], - legendText=[None], calendar=self.calendar) + legendText=[None], calendar=self.calendar, + firstYearXTicks=firstYearXTicks, + yearStrideXTicks=yearStrideXTicks) caption = u'Time Series of maximum Meridional Overturning ' \ u'Circulation at 26.5°N' @@ -350,11 +372,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) @@ -484,9 +516,9 @@ 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]) + years, months = get_files_year_month(inputFilesTseries, + self.historyStreams, + 'timeSeriesStatsMonthlyOutput') mocRegion = np.zeros(len(inputFilesTseries)) times = np.zeros(len(inputFilesTseries)) @@ -533,8 +565,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, diff --git a/mpas_analysis/ocean/time_series_antarctic_melt.py b/mpas_analysis/ocean/time_series_antarctic_melt.py index 8c668826b..79225fd82 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 @@ -5,17 +12,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 @@ -33,11 +41,10 @@ class TimeSeriesAntarcticMelt(AnalysisTask): refConfig : ``MpasAnalysisConfigParser`` The configuration options for the reference run (if any) - - Authors - ------- - Xylar Asay-Davis, Stephen Price """ + # Authors + # ------- + # Xylar Asay-Davis, Stephen Price def __init__(self, config, mpasTimeSeriesTask, refConfig=None): # {{{ @@ -54,11 +61,11 @@ def __init__(self, config, mpasTimeSeriesTask, refConfig=None): refConfig : ``MpasAnalysisConfigParser``, optional Configuration options for a reference run (if any) - - Authors - ------- - Xylar Asay-Davis """ + # Authors + # ------- + # Xylar Asay-Davis + # first, call the constructor from the base class (AnalysisTask) super(TimeSeriesAntarcticMelt, self).__init__( config=config, @@ -81,11 +88,11 @@ def setup_and_check(self): # {{{ ------ IOError If files are not present - - Authors - ------- - Xylar Asay-Davis """ + # Authors + # ------- + # Xylar Asay-Davis + # first, call setup_and_check from the base class (AnalysisTask), # which will perform some common setup, including storing: # self.inDirectory, self.plotsDirectory, self.namelist, self.streams @@ -173,11 +180,10 @@ def run_task(self): # {{{ """ Performs analysis of the time-series output of Antarctic sub-ice-shelf melt rates. - - Authors - ------- - Xylar Asay-Davis, Stephen Price """ + # Authors + # ------- + # Xylar Asay-Davis, Stephen Price self.logger.info("\nPlotting Antarctic melt rate time series...") @@ -334,6 +340,18 @@ def run_task(self): # {{{ lineWidths.append(1.2) legendText.append(refRunName) + if config.has_option(self.taskName, 'firstYearXTicks'): + firstYearXTicks = config.getint(self.taskName, + 'firstYearXTicks') + else: + firstYearXTicks = None + + if config.has_option(self.taskName, 'yearStrideXTicks'): + yearStrideXTicks = config.getint(self.taskName, + 'yearStrideXTicks') + else: + yearStrideXTicks = None + timeseries_analysis_plot(config, fields, movingAverageMonths, title, xLabel, yLabel, figureName, lineStyles=lineStyles, @@ -341,7 +359,9 @@ def run_task(self): # {{{ legendText=legendText, calendar=calendar, obsMean=obsMeltRate, obsUncertainty=obsMeltRateUnc, - obsLegend=list(obsDict.keys())) + obsLegend=list(obsDict.keys()), + firstYearXTicks=firstYearXTicks, + yearStrideXTicks=yearStrideXTicks) caption = 'Running Mean of Area-averaged Melt Rate under Ice ' \ 'Shelves in the {} Region'.format(title) @@ -362,11 +382,10 @@ def _compute_ice_shelf_fluxes(self): # {{{ """ Reads melt flux time series and computes regional total melt flux and mean melt rate. - - Authors - ------- - Xylar Asay-Davis, Stephen Price """ + # Authors + # ------- + # Xylar Asay-Davis, Stephen Price mpasTimeSeriesTask = self.mpasTimeSeriesTask config = self.config @@ -456,11 +475,11 @@ def _load_ice_shelf_fluxes(self, config): # {{{ """ Reads melt flux time series and computes regional total melt flux and mean melt rate. - - Authors - ------- - Xylar Asay-Davis """ + # Authors + # ------- + # Xylar Asay-Davis + baseDirectory = build_config_full_path( config, 'output', 'timeSeriesSubdirectory') diff --git a/mpas_analysis/ocean/time_series_ohc_anomaly.py b/mpas_analysis/ocean/time_series_ohc_anomaly.py index 0592abaf5..33128714f 100644 --- a/mpas_analysis/ocean/time_series_ohc_anomaly.py +++ b/mpas_analysis/ocean/time_series_ohc_anomaly.py @@ -1,26 +1,33 @@ # -*- coding: utf-8 -*- +# +# 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 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 class TimeSeriesOHCAnomaly(AnalysisTask): """ Performs analysis of ocean heat content (OHC) from time-series output. - - Authors - ------- - Xylar Asay-Davis, Milena Veneziani, Greg Streletz """ + # Authors + # ------- + # Xylar Asay-Davis, Milena Veneziani, Greg Streletz def __init__(self, config, mpasTimeSeriesTask, refConfig=None): # {{{ @@ -37,11 +44,11 @@ def __init__(self, config, mpasTimeSeriesTask, refConfig=None): refConfig : ``MpasAnalysisConfigParser``, optional Configuration options for a reference run (if any) - - Authors - ------- - Xylar Asay-Davis """ + # Authors + # ------- + # Xylar Asay-Davis + # first, call the constructor from the base class (AnalysisTask) super(TimeSeriesOHCAnomaly, self).__init__( config=config, diff --git a/mpas_analysis/ocean/time_series_salinity_anomaly.py b/mpas_analysis/ocean/time_series_salinity_anomaly.py index dba021329..7c362dd50 100644 --- a/mpas_analysis/ocean/time_series_salinity_anomaly.py +++ b/mpas_analysis/ocean/time_series_salinity_anomaly.py @@ -1,23 +1,30 @@ # -*- coding: utf-8 -*- +# +# 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 -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): """ Performs analysis of time series of salinity anomalies from the first simulation year as a function of depth. - - Authors - ------- - Xylar Asay-Davis """ + # Authors + # ------- + # Xylar Asay-Davis def __init__(self, config, mpasTimeSeriesTask): # {{{ """ @@ -30,11 +37,11 @@ def __init__(self, config, mpasTimeSeriesTask): # {{{ mpasTimeSeriesTask : ``MpasTimeSeriesTask`` The task that extracts the time series from MPAS monthly output - - Authors - ------- - Xylar Asay-Davis """ + # Authors + # ------- + # Xylar Asay-Davis + # first, call the constructor from the base class (AnalysisTask) super(TimeSeriesSalinityAnomaly, self).__init__( config=config, diff --git a/mpas_analysis/ocean/time_series_sst.py b/mpas_analysis/ocean/time_series_sst.py index 947d2b881..1695ea684 100644 --- a/mpas_analysis/ocean/time_series_sst.py +++ b/mpas_analysis/ocean/time_series_sst.py @@ -1,19 +1,27 @@ +# 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 -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): @@ -29,11 +37,10 @@ class TimeSeriesSST(AnalysisTask): refConfig : ``MpasAnalysisConfigParser`` Configuration options for a reference run (if any) - - Authors - ------- - Xylar Asay-Davis, Milena Veneziani """ + # Authors + # ------- + # Xylar Asay-Davis, Milena Veneziani def __init__(self, config, mpasTimeSeriesTask, refConfig=None): # {{{ @@ -50,11 +57,11 @@ def __init__(self, config, mpasTimeSeriesTask, refConfig=None): refConfig : ``MpasAnalysisConfigParser``, optional Configuration options for a reference run (if any) - - Authors - ------- - Xylar Asay-Davis """ + # Authors + # ------- + # Xylar Asay-Davis + # first, call the constructor from the base class (AnalysisTask) super(TimeSeriesSST, self).__init__( config=config, @@ -77,11 +84,11 @@ def setup_and_check(self): # {{{ ------ OSError If files are not present - - Authors - ------- - Xylar Asay-Davis """ + # Authors + # ------- + # Xylar Asay-Davis + # first, call setup_and_check from the base class (AnalysisTask), # which will perform some common setup, including storing: # self.inDirectory, self.plotsDirectory, self.namelist, self.streams @@ -121,11 +128,10 @@ def run_task(self): # {{{ """ Performs analysis of the time-series output of sea-surface temperature (SST). - - Authors - ------- - Xylar Asay-Davis, Milena Veneziani """ + # Authors + # ------- + # Xylar Asay-Davis, Milena Veneziani self.logger.info("\nPlotting SST time series...") @@ -246,11 +252,25 @@ def run_task(self): # {{{ lineWidths.append(1.5) legendText.append(preprocessedReferenceRunName) + if config.has_option(self.taskName, 'firstYearXTicks'): + firstYearXTicks = config.getint(self.taskName, + 'firstYearXTicks') + else: + firstYearXTicks = None + + if config.has_option(self.taskName, 'yearStrideXTicks'): + yearStrideXTicks = config.getint(self.taskName, + 'yearStrideXTicks') + else: + yearStrideXTicks = None + timeseries_analysis_plot(config, fields, movingAveragePoints, title, xLabel, yLabel, figureName, lineStyles=lineStyles, lineWidths=lineWidths, - legendText=legendText, calendar=calendar) + legendText=legendText, calendar=calendar, + firstYearXTicks=firstYearXTicks, + yearStrideXTicks=yearStrideXTicks) caption = 'Running Mean of {} Sea Surface Temperature'.format( region) diff --git a/mpas_analysis/ocean/time_series_temperature_anomaly.py b/mpas_analysis/ocean/time_series_temperature_anomaly.py index 4897795f3..14f326cec 100644 --- a/mpas_analysis/ocean/time_series_temperature_anomaly.py +++ b/mpas_analysis/ocean/time_series_temperature_anomaly.py @@ -1,23 +1,30 @@ # -*- coding: utf-8 -*- +# +# 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 -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): """ Performs analysis of time series of temperature anomalies from the first simulation year as a function of depth. - - Authors - ------- - Xylar Asay-Davis """ + # Authors + # ------- + # Xylar Asay-Davis def __init__(self, config, mpasTimeSeriesTask): # {{{ """ @@ -30,11 +37,11 @@ def __init__(self, config, mpasTimeSeriesTask): # {{{ mpasTimeSeriesTask : ``MpasTimeSeriesTask`` The task that extracts the time series from MPAS monthly output - - Authors - ------- - Xylar Asay-Davis """ + # Authors + # ------- + # Xylar Asay-Davis + # first, call the constructor from the base class (AnalysisTask) super(TimeSeriesTemperatureAnomaly, self).__init__( config=config, diff --git a/mpas_analysis/ocean/utility.py b/mpas_analysis/ocean/utility.py index 8600977ef..f6efc927d 100644 --- a/mpas_analysis/ocean/utility.py +++ b/mpas_analysis/ocean/utility.py @@ -1,10 +1,16 @@ +# 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 - -Authors -------- -Xylar Asay-Davis """ +# Authors +# ------- +# Xylar Asay-Davis from __future__ import absolute_import, division, print_function, \ unicode_literals @@ -34,11 +40,10 @@ def compute_zmid(bottomDepth, maxLevelCell, layerThickness): # {{{ zMid : ``xarray.DataArray`` the vertical coordinate defining the middle of each layer, masked below the bathymetry - - Authors - ------- - Xylar Asay-Davis """ + # Authors + # ------- + # Xylar Asay-Davis nVertLevels = \ layerThickness.shape[layerThickness.dims.index('nVertLevels')] 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..88748ef2d 100644 --- a/mpas_analysis/sea_ice/climatology_map_sea_ice_conc.py +++ b/mpas_analysis/sea_ice/climatology_map_sea_ice_conc.py @@ -1,30 +1,38 @@ +# 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 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): # {{{ """ An analysis task for comparison of sea ice concentration against observations - - Authors - ------- - Luke Van Roekel, Xylar Asay-Davis, Milena Veneziani """ + # Authors + # ------- + # Luke Van Roekel, Xylar Asay-Davis, Milena Veneziani + def __init__(self, config, mpasClimatologyTask, hemisphere, refConfig=None): # {{{ """ @@ -43,11 +51,11 @@ def __init__(self, config, mpasClimatologyTask, hemisphere, refConfig : ``MpasAnalysisConfigParser``, optional Configuration options for a reference run (if any) - - Authors - ------- - Xylar Asay-Davis """ + # Authors + # ------- + # Xylar Asay-Davis + taskName = 'climatologyMapSeaIceConc{}'.format(hemisphere) fieldName = 'seaIceConc' @@ -218,11 +226,10 @@ def _add_ref_tasks(self, seasons, comparisonGridNames, hemisphere, class RemapObservedConcClimatology(RemapObservedClimatologySubtask): # {{{ """ A subtask for reading and remapping sea ice concentration observations - - Authors - ------- - Xylar Asay-Davis """ + # Authors + # ------- + # Xylar Asay-Davis def get_observation_descriptor(self, fileName): # {{{ ''' @@ -237,11 +244,10 @@ def get_observation_descriptor(self, fileName): # {{{ ------- obsDescriptor : ``MeshDescriptor`` The descriptor for the observation grid - - Authors - ------- - Xylar Asay-Davis ''' + # Authors + # ------- + # Xylar Asay-Davis # create a descriptor of the observation grid using the lat/lon # coordinates @@ -264,11 +270,10 @@ def build_observational_dataset(self, fileName): # {{{ ------- dsObs : ``xarray.Dataset`` The observational dataset - - Authors - ------- - Xylar Asay-Davis ''' + # Authors + # ------- + # Xylar Asay-Davis dsObs = xr.open_dataset(fileName) dsObs.rename({'AICE': 'seaIceConc'}, inplace=True) 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..03bf9bc75 100644 --- a/mpas_analysis/sea_ice/climatology_map_sea_ice_thick.py +++ b/mpas_analysis/sea_ice/climatology_map_sea_ice_thick.py @@ -1,30 +1,38 @@ +# 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 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): # {{{ """ An analysis task for comparison of sea ice thickness against observations - - Authors - ------- - Luke Van Roekel, Xylar Asay-Davis, Milena Veneziani """ + # Authors + # ------- + # Luke Van Roekel, Xylar Asay-Davis, Milena Veneziani + def __init__(self, config, mpasClimatologyTask, hemisphere, refConfig=None): # {{{ """ @@ -43,11 +51,11 @@ def __init__(self, config, mpasClimatologyTask, hemisphere, refConfig : ``MpasAnalysisConfigParser``, optional Configuration options for a reference run (if any) - - Authors - ------- - Xylar Asay-Davis """ + # Authors + # ------- + # Xylar Asay-Davis + taskName = 'climatologyMapSeaIceThick{}'.format(hemisphere) fieldName = 'seaIceThick' @@ -163,11 +171,10 @@ def __init__(self, config, mpasClimatologyTask, hemisphere, class RemapObservedThickClimatology(RemapObservedClimatologySubtask): # {{{ """ A subtask for reading and remapping sea ice thickness observations - - Authors - ------- - Xylar Asay-Davis """ + # Authors + # ------- + # Xylar Asay-Davis def get_observation_descriptor(self, fileName): # {{{ ''' @@ -182,11 +189,10 @@ def get_observation_descriptor(self, fileName): # {{{ ------- obsDescriptor : ``MeshDescriptor`` The descriptor for the observation grid - - Authors - ------- - Xylar Asay-Davis ''' + # Authors + # ------- + # Xylar Asay-Davis # create a descriptor of the observation grid using the lat/lon # coordinates @@ -209,11 +215,10 @@ def build_observational_dataset(self, fileName): # {{{ ------- dsObs : ``xarray.Dataset`` The observational dataset - - Authors - ------- - Xylar Asay-Davis ''' + # Authors + # ------- + # Xylar Asay-Davis dsObs = xr.open_dataset(fileName) dsObs.rename({'HI': 'seaIceThick'}, inplace=True) diff --git a/mpas_analysis/sea_ice/plot_climatology_map_subtask.py b/mpas_analysis/sea_ice/plot_climatology_map_subtask.py index 9d5bf9ad2..bf256b593 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 @@ -7,14 +14,14 @@ import xarray as xr -from ..shared import AnalysisTask +from mpas_analysis.shared import AnalysisTask -from ..shared.plot.plotting import plot_polar_comparison, \ - setup_colormap +from mpas_analysis.shared.plot.plotting import plot_polar_comparison -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): # {{{ @@ -82,11 +89,10 @@ class PlotClimatologyMapSubtask(AnalysisTask): # {{{ galleryName : str the name of the gallery in which this plot belongs - - Authors - ------- - Xylar Asay-Davis, Milena Veneziani """ + # Authors + # ------- + # Xylar Asay-Davis, Milena Veneziani def __init__(self, parentTask, hemisphere, season, comparisonGridName, remapMpasClimatologySubtask, remapObsClimatologySubtask=None, @@ -125,12 +131,10 @@ def __init__(self, parentTask, hemisphere, season, comparisonGridName, subtaskSuffix : str, optional A suffix on the subtask to ensure that it is unique (e.g. the observations being plotted) - - Authors - ------- - Xylar Asay-Davis - ''' + # Authors + # ------- + # Xylar Asay-Davis self.hemisphere = hemisphere self.season = season @@ -212,11 +216,11 @@ def set_plot_info(self, outFileLabel, fieldNameInTitle, mpasFieldName, maskValue : float, optional a value to mask out in plots - - Authors - ------- - Xylar Asay-Davis """ + # Authors + # ------- + # Xylar Asay-Davis + self.outFileLabel = outFileLabel self.fieldNameInTitle = fieldNameInTitle self.mpasFieldName = mpasFieldName @@ -239,11 +243,11 @@ def set_plot_info(self, outFileLabel, fieldNameInTitle, mpasFieldName, def setup_and_check(self): # {{{ """ Perform steps to set up the analysis and check for errors in the setup. - - Authors - ------- - Xylar Asay-Davis """ + # Authors + # ------- + # Xylar Asay-Davis + # first, call setup_and_check from the base class (AnalysisTask), # which will perform some common setup super(PlotClimatologyMapSubtask, self).setup_and_check() @@ -270,11 +274,10 @@ def run_task(self): # {{{ """ Performs analysis of sea-ice properties by comparing with previous model results and/or observations. - - Authors - ------- - Xylar Asay-Davis, Milena Veneziani """ + # Authors + # ------- + # Xylar Asay-Davis, Milena Veneziani config = self.config season = self.season @@ -297,11 +300,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, @@ -372,10 +370,7 @@ def run_task(self): # {{{ modelOutput, refOutput, difference, - colormapResult, - colorbarLevelsResult, - colormapDifference, - colorbarLevelsDifference, + sectionName, title=title, fileout=fileout, plotProjection=plotProjection, diff --git a/mpas_analysis/sea_ice/time_series.py b/mpas_analysis/sea_ice/time_series.py index c890964f3..deca1ac27 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 @@ -5,23 +12,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): @@ -37,11 +45,10 @@ class TimeSeriesSeaIce(AnalysisTask): refConfig : ``MpasAnalysisConfigParser`` Configuration options for a reference run (if any) - - Authors - ------- - Xylar Asay-Davis, Milena Veneziani """ + # Authors + # ------- + # Xylar Asay-Davis, Milena Veneziani def __init__(self, config, mpasTimeSeriesTask, refConfig=None): # {{{ @@ -58,11 +65,11 @@ def __init__(self, config, mpasTimeSeriesTask, refConfig : ``MpasAnalysisConfigParser``, optional Configuration options for a reference run (if any) - - Authors - ------- - Xylar Asay-Davis """ + # Authors + # ------- + # Xylar Asay-Davis + # first, call the constructor from the base class (AnalysisTask) super(TimeSeriesSeaIce, self).__init__( config=config, @@ -85,11 +92,11 @@ def setup_and_check(self): # {{{ ------ OSError If files are not present - - Authors - ------- - Xylar Asay-Davis """ + # Authors + # ------- + # Xylar Asay-Davis + # first, call setup_and_check from the base class (AnalysisTask), # which will perform some common setup, including storing: # self.runDirectory , self.historyDirectory, self.plotsDirectory, @@ -180,11 +187,10 @@ def setup_and_check(self): # {{{ def run_task(self): # {{{ """ Performs analysis of time series of sea-ice properties. - - Authors - ------- - Xylar Asay-Davis, Milena Veneziani """ + # Authors + # ------- + # Xylar Asay-Davis, Milena Veneziani self.logger.info("\nPlotting sea-ice area and volume time series...") @@ -412,6 +418,18 @@ def run_task(self): # {{{ lineStyles.append('g-') lineWidths.append(1.2) + if config.has_option(self.taskName, 'firstYearXTicks'): + firstYearXTicks = config.getint(self.taskName, + 'firstYearXTicks') + else: + firstYearXTicks = None + + if config.has_option(self.taskName, 'yearStrideXTicks'): + yearStrideXTicks = config.getint(self.taskName, + 'yearStrideXTicks') + else: + yearStrideXTicks = None + # separate plots for nothern and southern hemispheres timeseries_analysis_plot(config, dsvalues, movingAveragePoints, @@ -422,7 +440,10 @@ def run_task(self): # {{{ lineWidths=lineWidths, legendText=legendText, titleFontSize=titleFontSize, - calendar=calendar) + calendar=calendar, + firstYearXTicks=firstYearXTicks, + yearStrideXTicks=yearStrideXTicks) + filePrefix = '{}{}_{}'.format(variableName, hemisphere, mainRunName) @@ -490,11 +511,11 @@ def _replicate_cycle(self, ds, dsToReplicate, calendar): # {{{ -------- dsShift : a cyclicly repeated version of `dsToReplicte` covering the range of time of `ds`. - - Authors - ------- - Xylar Asay-Davis, Milena Veneziani """ + # Authors + # ------- + # Xylar Asay-Davis, Milena Veneziani + dsStartTime = days_to_datetime(ds.Time.min(), calendar=calendar) dsEndTime = days_to_datetime(ds.Time.max(), calendar=calendar) repStartTime = days_to_datetime(dsToReplicate.Time.min(), 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..3d71f7d9b 100644 --- a/mpas_analysis/shared/analysis_task.py +++ b/mpas_analysis/shared/analysis_task.py @@ -1,11 +1,16 @@ +# 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. - -Authors -------- -Xylar Asay-Davis - ''' +# Authors +# ------- +# Xylar Asay-Davis from __future__ import absolute_import, division, print_function, \ unicode_literals @@ -16,8 +21,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): # {{{ @@ -79,12 +85,10 @@ class AnalysisTask(Process): # {{{ logger : ``logging.Logger`` A logger for output during the run phase of an analysis task - - Authors - ------- - Xylar Asay-Davis - ''' + # Authors + # ------- + # Xylar Asay-Davis # flags for run status UNSET = 0 @@ -124,11 +128,11 @@ def __init__(self, config, taskName, componentName, tags=[], subtaskName : str, optional If this is a subtask of ``taskName``, the name of the subtask - - Authors - ------- - Xylar Asay-Davis ''' + # Authors + # ------- + # Xylar Asay-Davis + if subtaskName is None: self.fullTaskName = taskName self.printTaskName = taskName @@ -173,11 +177,10 @@ def setup_and_check(self): # {{{ analysis-specific setup. For example, this function could check if necessary observations and other data files are found, then, determine the list of files to be read when the analysis is run. - - Authors - ------- - Xylar Asay-Davis ''' + # Authors + # ------- + # Xylar Asay-Davis # read parameters from config file # the run directory contains the restart files @@ -227,11 +230,11 @@ def run_task(self): # {{{ ''' Run the analysis. Each task should override this function to do the work of computing and/or plotting analysis - - Authors - ------- - Xylar Asay-Davis ''' + # Authors + # ------- + # Xylar Asay-Davis + return # }}} def run_after(self, task): # {{{ @@ -246,11 +249,10 @@ def run_after(self, task): # {{{ ---------- task : ``AnalysisTask`` The task that should finish before this one begins - - Authors - ------- - Xylar Asay-Davis ''' + # Authors + # ------- + # Xylar Asay-Davis self.runAfterTasks.append(task) # }}} @@ -266,11 +268,10 @@ def add_subtask(self, subtask): # {{{ ---------- subtask : ``AnalysisTask`` The subtask to run as part of this task - - Authors - ------- - Xylar Asay-Davis ''' + # Authors + # ------- + # Xylar Asay-Davis if subtask not in self.subtasks: self.subtasks.append(subtask) @@ -287,11 +288,11 @@ def run(self, writeLogFile=True): # {{{ Otherwise, the internal logger ``self.logger`` points to stdout and no log file is created. The intention is for logging to take place in parallel mode but not in serial mode. - - Authors - ------- - Xylar Asay-Davis ''' + # Authors + # ------- + # Xylar Asay-Davis + # redirect output to a log file if writeLogFile: self.logger = logging.getLogger(self.fullTaskName) @@ -358,11 +359,10 @@ def check_generate(self): ------ ValueError : If one of ``self.taskName``, ``self.componentName`` or ``self.tags`` has not been set. - - Authors - ------- - Xylar Asay-Davis ''' + # Authors + # ------- + # Xylar Asay-Davis for memberName in ['taskName', 'componentName', 'tags']: if not hasattr(self, memberName): @@ -436,11 +436,10 @@ def check_analysis_enabled(self, analysisOptionName, default=False, If the given analysis option is not found and ``default`` is not ``True`` or if the analysis option is found and is ``False``. The exception is only raised if ``raiseException = True``. - - Authors - ------- - Xylar Asay-Davis ''' + # Authors + # ------- + # Xylar Asay-Davis try: optionName = analysisOptionName @@ -473,11 +472,10 @@ def set_start_end_date(self, section): # {{{ The name of a section in the config file containing ``startYear`` and ``endYear`` options. ``section`` is typically one of ``climatology``, ``timeSeries`` or ``index`` - - Authors - ------- - Xylar Asay-Davis ''' + # Authors + # ------- + # Xylar Asay-Davis if not self.config.has_option(section, 'startDate'): startDate = '{:04d}-01-01_00:00:00'.format( @@ -497,11 +495,10 @@ class AnalysisFormatter(logging.Formatter): # {{{ Modified from: https://stackoverflow.com/a/8349076/7728169 - - Authors - ------- - Xylar Asay-Davis """ + # Authors + # ------- + # Xylar Asay-Davis # printing error messages without a prefix because they are sometimes # errors and sometimes only warnings sent to stderr 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..c8d0599f3 100644 --- a/mpas_analysis/shared/climatology/climatology.py +++ b/mpas_analysis/shared/climatology/climatology.py @@ -1,10 +1,16 @@ +# 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 - -Authors -------- -Xylar Asay-Davis """ +# Authors +# ------- +# Xylar Asay-Davis from __future__ import absolute_import, division, print_function, \ unicode_literals @@ -13,17 +19,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, @@ -61,11 +69,10 @@ def get_remapper(config, sourceDescriptor, comparisonDescriptor, remapper : ``Remapper`` object A remapper that can be used to remap files or data sets from the source grid or mesh to the comparison grid. - - Authors - ------- - Xylar Asay-Davis """ + # Authors + # ------- + # Xylar Asay-Davis mappingFileName = None @@ -137,11 +144,10 @@ def compute_monthly_climatology(ds, calendar=None, maskVaries=True): # {{{ A data set without the ``'Time'`` coordinate containing the mean of ds over all months in monthValues, weighted by the number of days in each month. - - Authors - ------- - Xylar Asay-Davis """ + # Authors + # ------- + # Xylar Asay-Davis def compute_one_month_climatology(ds): monthValues = list(ds.month.values) @@ -191,11 +197,10 @@ def compute_climatology(ds, monthValues, calendar=None, A data set without the ``'Time'`` coordinate containing the mean of ds over all months in monthValues, weighted by the number of days in each month. - - Authors - ------- - Xylar Asay-Davis """ + # Authors + # ------- + # Xylar Asay-Davis ds = add_years_months_days_in_month(ds, calendar) @@ -234,11 +239,10 @@ def add_years_months_days_in_month(ds, calendar=None): # {{{ ds : object of same type as ``ds`` The data set with ``year``, ``month`` and ``daysInMonth`` data arrays added (if not already present) - - Authors - ------- - Xylar Asay-Davis ''' + # Authors + # ------- + # Xylar Asay-Davis if ('year' in ds.coords and 'month' in ds.coords and 'daysInMonth' in ds.coords): @@ -319,15 +323,16 @@ def remap_and_write_climatology(config, climatologyDataSet, ------- remappedClimatology : ``xarray.DataSet`` or ``xarray.DataArray`` object A data set containing the remapped climatology - - Authors - ------- - Xylar Asay-Davis """ + # Authors + # ------- + # Xylar Asay-Davis + 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 @@ -363,11 +368,10 @@ def get_unmasked_mpas_climatology_directory(config): # {{{ ---------- config : ``MpasAnalysisConfigParser`` configuration options - - Authors - ------- - Xylar Asay-Davis """ + # Authors + # ------- + # Xylar Asay-Davis climatologyBaseDirectory = build_config_full_path( config, 'output', 'mpasClimatologySubdirectory') @@ -396,11 +400,10 @@ def get_unmasked_mpas_climatology_file_name(config, season, componentName): componentName : {'ocean', 'seaIce'} The MPAS component for which the climatology is being computed - - Authors - ------- - Xylar Asay-Davis """ + # Authors + # ------- + # Xylar Asay-Davis startYear = config.getint('climatology', 'startYear') endYear = config.getint('climatology', 'endYear') @@ -450,11 +453,10 @@ def get_masked_mpas_climatology_file_name(config, season, componentName, climatologyName : str The name of the climatology (typically the name of a field to mask and later remap) - - Authors - ------- - Xylar Asay-Davis """ + # Authors + # ------- + # Xylar Asay-Davis startYear = config.getint('climatology', 'startYear') endYear = config.getint('climatology', 'endYear') @@ -518,11 +520,10 @@ def get_remapped_mpas_climatology_file_name(config, season, componentName, comparisonGridName : {'latlon', 'antarctic'} The name of the comparison grid to use for remapping - - Authors - ------- - Xylar Asay-Davis """ + # Authors + # ------- + # Xylar Asay-Davis startYear = config.getint('climatology', 'startYear') endYear = config.getint('climatology', 'endYear') @@ -571,11 +572,11 @@ def _compute_masked_mean(ds, maskVaries): # {{{ Compute the time average of data set, masked out where the variables in ds are NaN and, if ``maskVaries == True``, weighting by the number of days used to compute each monthly mean time in ds. - - Authors - ------- - Xylar Asay-Davis ''' + # Authors + # ------- + # Xylar Asay-Davis + def ds_to_weights(ds): # make an identical data set to ds but replacing all data arrays with # nonnull applied to that data array @@ -612,11 +613,10 @@ def ds_to_weights(ds): def _matches_comparison(obsDescriptor, comparisonDescriptor): # {{{ ''' Determine if the two meshes are the same - - Authors - ------- - Xylar Asay-Davis ''' + # Authors + # ------- + # Xylar Asay-Davis if isinstance(obsDescriptor, ProjectionGridDescriptor) and \ isinstance(comparisonDescriptor, ProjectionGridDescriptor): @@ -653,11 +653,10 @@ def _setup_climatology_caching(ds, startYearClimo, endYearClimo, ''' Determine which cache files already exist, which are incomplete and which years are present in each cache file (whether existing or to be created). - - Authors - ------- - Xylar Asay-Davis ''' + # Authors + # ------- + # Xylar Asay-Davis cacheInfo = [] @@ -716,11 +715,10 @@ def _cache_individual_climatologies(ds, cacheInfo, printProgress, calendar): # {{{ ''' Cache individual climatologies for later aggregation. - - Authors - ------- - Xylar Asay-Davis ''' + # Authors + # ------- + # Xylar Asay-Davis for cacheIndex, info in enumerate(cacheInfo): outputFileClimo, done, yearString = info @@ -753,11 +751,10 @@ def _cache_aggregated_climatology(startYearClimo, endYearClimo, cachePrefix, cacheInfo): # {{{ ''' Cache aggregated climatology from individual climatologies. - - Authors - ------- - Xylar Asay-Davis ''' + # Authors + # ------- + # Xylar Asay-Davis yearString, fileSuffix = _get_year_string(startYearClimo, endYearClimo) outputFileClimo = '{}_{}.nc'.format(cachePrefix, fileSuffix) diff --git a/mpas_analysis/shared/climatology/comparison_descriptors.py b/mpas_analysis/shared/climatology/comparison_descriptors.py index 1c91c7476..24bbaf65b 100644 --- a/mpas_analysis/shared/climatology/comparison_descriptors.py +++ b/mpas_analysis/shared/climatology/comparison_descriptors.py @@ -1,10 +1,16 @@ +# 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 - -Authors -------- -Xylar Asay-Davis """ +# Authors +# ------- +# Xylar Asay-Davis from __future__ import absolute_import, division, print_function, \ unicode_literals @@ -12,9 +18,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): # {{{ @@ -33,11 +40,11 @@ def get_comparison_descriptor(config, comparisonGridName): # {{{ ------ ValueError If comparisonGridName does not describe a known comparions grid - - Authors - ------- - Xylar Asay-Davis """ + # Authors + # ------- + # Xylar Asay-Davis + if comparisonGridName == 'latlon': comparisonDescriptor = \ _get_lat_lon_comparison_descriptor(config) @@ -58,11 +65,11 @@ def get_antarctic_stereographic_projection(): # {{{ ------- projection : ``pyproj.Proj`` object The projection - - Authors - ------- - Xylar Asay-Davis """ + # Authors + # ------- + # Xylar Asay-Davis + projection = pyproj.Proj('+proj=stere +lat_ts=-71.0 +lat_0=-90 +lon_0=0.0 ' '+k_0=1.0 +x_0=0.0 +y_0=0.0 +ellps=WGS84') @@ -83,11 +90,11 @@ def _get_lat_lon_comparison_descriptor(config): # {{{ ------- descriptor : ``LatLonGridDescriptor`` object A descriptor of the lat/lon grid - - Authors - ------- - Xylar Asay-Davis """ + # Authors + # ------- + # Xylar Asay-Davis + climSection = 'climatology' comparisonLatRes = config.getWithDefault(climSection, @@ -121,11 +128,11 @@ def _get_antarctic_stereographic_comparison_descriptor(config): # {{{ ------- descriptor : ``ProjectionGridDescriptor`` object A descriptor of the Antarctic comparison grid - - Authors - ------- - Xylar Asay-Davis """ + # Authors + # ------- + # Xylar Asay-Davis + climSection = 'climatology' comparisonStereoWidth = config.getfloat(climSection, diff --git a/mpas_analysis/shared/climatology/mpas_climatology_task.py b/mpas_analysis/shared/climatology/mpas_climatology_task.py index fa5d05824..fe5d4e269 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 @@ -7,11 +14,15 @@ 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 +from ..io.utility import build_config_full_path, make_directories, \ + get_files_year_month + class MpasClimatologyTask(AnalysisTask): # {{{ ''' @@ -25,6 +36,10 @@ class MpasClimatologyTask(AnalysisTask): # {{{ A list of variable names in ``timeSeriesStatsMonthly`` to be included in the climatologies + allVariables : list of str + A list of all available variable names in ``timeSeriesStatsMonthly`` + used to raise an exception when an unavailable variable is requested + seasons : list of str A list of seasons (keys in ``shared.constants.monthDictionary``) over which the climatology should be computed or ['none'] if only @@ -41,11 +56,10 @@ class MpasClimatologyTask(AnalysisTask): # {{{ startYear, endYear : int The start and end years of the climatology - - Authors - ------- - Xylar Asay-Davis ''' + # Authors + # ------- + # Xylar Asay-Davis def __init__(self, config, componentName, taskName=None): # {{{ ''' @@ -63,11 +77,11 @@ def __init__(self, config, componentName, taskName=None): # {{{ taskName : str, optional the name of the task, defaults to mpasClimatology - - Authors - ------- - Xylar Asay-Davis ''' + # Authors + # ------- + # Xylar Asay-Davis + self.variableList = [] self.seasons = [] @@ -86,6 +100,8 @@ def __init__(self, config, componentName, taskName=None): # {{{ suffix = componentName[0].upper() + componentName[1:] taskName = 'mpasClimatology{}'.format(suffix) + self.allVariables = None + # call the constructor from the base class (AnalysisTask) super(MpasClimatologyTask, self).__init__( config=config, @@ -111,12 +127,31 @@ def add_variables(self, variableList, seasons=None): # {{{ to be computed or ['none'] (not ``None``) if only monthly climatologies are needed. - Authors - ------- - Xylar Asay-Davis + Raises + ------ + ValueError + if this funciton is called before this task has been set up (so + the list of available variables has not yet been set) or if one + or more of the requested variables is not available in the + ``timeSeriesStatsMonthly`` output. ''' + # Authors + # ------- + # Xylar Asay-Davis + + if self.allVariables is None: + raise ValueError('add_variables() can only be called after ' + 'setup_and_check() in MpasClimatologyTask.\n' + 'Presumably tasks were added in the wrong order ' + 'or add_variables() is being called in the wrong ' + 'place.') for variable in variableList: + if variable not in self.allVariables: + raise ValueError( + '{} is not available in timeSeriesStatsMonthly ' + 'output:\n{}'.format(variable, self.allVariables)) + if variable not in self.variableList: self.variableList.append(variable) @@ -137,11 +172,10 @@ def setup_and_check(self): # {{{ If a restart file is not available from which to read mesh information or if no history files are available from which to compute the climatology in the desired time range. - - Authors - ------- - Xylar Asay-Davis ''' + # Authors + # ------- + # Xylar Asay-Davis # first, call setup_and_check from the base class (AnalysisTask), # which will perform some common setup, including storing: @@ -167,18 +201,21 @@ 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() + + with xarray.open_dataset(self.inputFiles[0]) as ds: + self.allVariables = list(ds.data_vars.keys()) # }}} def run_task(self): # {{{ ''' Compute the requested climatologies - - Authors - ------- - Xylar Asay-Davis ''' + # Authors + # ------- + # Xylar Asay-Davis if len(self.variableList) == 0: # nothing to do @@ -216,7 +253,7 @@ def run_task(self): # {{{ if not allExist: self._compute_climatologies_with_ncclimo( - inDirectory=self.historyDirectory, + inDirectory=self.symlinkDirectory, outDirectory=climatologyDirectory) # }}} @@ -235,35 +272,42 @@ def get_file_name(self, season): # {{{ ------- fileName : str The path to the climatology file for the specified season. - - Authors - ------- - Xylar Asay-Davis """ + # Authors + # ------- + # Xylar Asay-Davis return get_unmasked_mpas_climatology_file_name(self.config, season, self.componentName) # }}} - 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. - Authors + Returns ------- - Xylar Asay-Davis + symlinkDirectory : str + The path to the symlinks created for each timeSeriesStatsMonthly + input file """ + # Authors + # ------- + # Xylar Asay-Davis config = self.config 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 @@ -302,6 +346,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, diff --git a/mpas_analysis/shared/climatology/remap_mpas_climatology_subtask.py b/mpas_analysis/shared/climatology/remap_mpas_climatology_subtask.py index 3e9d55067..5a7f6b99d 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 @@ -6,20 +13,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): # {{{ @@ -55,14 +65,19 @@ class RemapMpasClimatologySubtask(AnalysisTask): # {{{ If ``comparisonGridName`` is not ``None``, the name of a restart file from which the MPAS mesh can be read. - Authors - ------- - Xylar Asay-Davis + 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 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 @@ -101,10 +116,18 @@ def __init__(self, mpasClimatologyTask, parentTask, climatologyName, subtaskName : str, optional The name of the subtask - Authors - ------- - Xylar Asay-Davis + 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 + tags = ['climatology'] # call the constructor from the base class (AnalysisTask) @@ -130,6 +153,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): # {{{ @@ -142,11 +171,10 @@ def setup_and_check(self): # {{{ If a restart file is not available from which to read mesh information or if no history files are available from which to compute the climatology in the desired time range. - - Authors - ------- - Xylar Asay-Davis ''' + # Authors + # ------- + # Xylar Asay-Davis # first, call setup_and_check from the base class (AnalysisTask), # which will perform some common setup, including storing: @@ -181,11 +209,10 @@ def setup_and_check(self): # {{{ def run_task(self): # {{{ ''' Compute the requested climatologies - - Authors - ------- - Xylar Asay-Davis ''' + # Authors + # ------- + # Xylar Asay-Davis self.logger.info('\nRemapping climatology {}'.format( self.climatologyName)) @@ -234,11 +261,10 @@ def get_masked_file_name(self, season): # {{{ ------- fileName : str The path to the climatology file for the specified season. - - Authors - ------- - Xylar Asay-Davis """ + # Authors + # ------- + # Xylar Asay-Davis fileName = get_masked_mpas_climatology_file_name(self.config, season, @@ -265,11 +291,10 @@ def get_remapped_file_name(self, season, comparisonGridName): # {{{ ------- fileName : str The path to the climatology file for the specified season. - - Authors - ------- - Xylar Asay-Davis """ + # Authors + # ------- + # Xylar Asay-Davis fileName = get_remapped_mpas_climatology_file_name( self.config, season, self.componentName, self.climatologyName, @@ -281,11 +306,11 @@ def _setup_remappers(self): # {{{ """ Set up the remappers for remapping from the MPAS to the comparison grids. - - Authors - ------- - Xylar Asay-Davis """ + # Authors + # ------- + # Xylar Asay-Davis + config = self.config # make reamppers @@ -326,11 +351,10 @@ def customize_masked_climatology(self, climatology): # {{{ climatology : ``xarray.Dataset``` The same data set with any custom fields added or modifications made - - Authors - ------- - Xylar Asay-Davis """ + # Authors + # ------- + # Xylar Asay-Davis return climatology # }}} @@ -348,22 +372,20 @@ def customize_remapped_climatology(self, climatology): # {{{ climatology : ``xarray.Dataset``` The same data set with any custom fields added or modifications made - - Authors - ------- - Xylar Asay-Davis """ + # Authors + # ------- + # Xylar Asay-Davis return climatology # }}} def _setup_file_names(self): # {{{ """ Create a dictionary of file names and directories for this climatology - - Authors - ------- - Xylar Asay-Davis """ + # Authors + # ------- + # Xylar Asay-Davis config = self.config climatologyBaseDirectory = build_config_full_path( @@ -499,25 +521,20 @@ def _remap(self, inFileName, outFileName, remapper, comparisonGridName): comparisonGridNames : {'latlon', 'antarctic'} The name of the comparison grid to use for remapping. - - Authors - ------- - Xylar Asay-Davis """ + # Authors + # ------- + # Xylar Asay-Davis + if remapper.mappingFileName is None: # 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, diff --git a/mpas_analysis/shared/climatology/remap_observed_climatology_subtask.py b/mpas_analysis/shared/climatology/remap_observed_climatology_subtask.py index ac4c14af6..532490916 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 @@ -5,17 +12,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): # {{{ @@ -37,10 +46,10 @@ class RemapObservedClimatologySubtask(AnalysisTask): # {{{ comparisonGridNames : list of {'latlon', 'antarctic'} The name(s) of the comparison grid to use for remapping. - Authors - ------- - Xylar Asay-Davis """ + # Authors + # ------- + # Xylar Asay-Davis def __init__(self, parentTask, seasons, fileName, outFilePrefix, comparisonGridNames=['latlon'], @@ -71,12 +80,10 @@ def __init__(self, parentTask, seasons, fileName, outFilePrefix, subtaskName : str, optional The name of the subtask - - Authors - ------- - Xylar Asay-Davis - ''' + # Authors + # ------- + # Xylar Asay-Davis self.seasons = seasons self.fileName = fileName @@ -97,11 +104,11 @@ def __init__(self, parentTask, seasons, fileName, outFilePrefix, def setup_and_check(self): # {{{ """ Perform steps to set up the analysis and check for errors in the setup. - - Authors - ------- - Xylar Asay-Davis """ + # Authors + # ------- + # Xylar Asay-Davis + # call setup_and_check from the base class (AnalysisTask), # which will perform some common setup, including storing: # self.runDirectory , self.historyDirectory, self.plotsDirectory, @@ -125,11 +132,10 @@ def setup_and_check(self): # {{{ def run_task(self): # {{{ """ Performs remapping of obsrevations to the comparsion grid - - Authors - ------- - Xylar Asay-Davis """ + # Authors + # ------- + # Xylar Asay-Davis config = self.config @@ -198,11 +204,10 @@ def get_observation_descriptor(self, fileName): # {{{ ------- obsDescriptor : ``MeshDescriptor`` The descriptor for the observation grid - - Authors - ------- - Xylar Asay-Davis ''' + # Authors + # ------- + # Xylar Asay-Davis return None # }}} @@ -221,11 +226,10 @@ def build_observational_dataset(self, fileName): # {{{ ------- dsObs : ``xarray.Dataset`` The observational dataset - - Authors - ------- - Xylar Asay-Davis ''' + # Authors + # ------- + # Xylar Asay-Davis return None # }}} @@ -253,11 +257,10 @@ def get_file_name(self, stage, season=None, comparisonGridName=None): ------- fileName : str The path to the climatology file for the specified season. - - Authors - ------- - Xylar Asay-Davis """ + # Authors + # ------- + # Xylar Asay-Davis config = self.config obsSection = '{}Observations'.format(self.componentName) @@ -314,11 +317,11 @@ def _setup_remappers(self, fileName): # {{{ ---------- fileName : str The name of the observation file used to determine the source grid - - Authors - ------- - Xylar Asay-Davis """ + # Authors + # ------- + # Xylar Asay-Davis + config = self.config sectionName = '{}Observations'.format(self.componentName) diff --git a/mpas_analysis/shared/constants/constants.py b/mpas_analysis/shared/constants/constants.py index 9f901aadf..7635ca678 100644 --- a/mpas_analysis/shared/constants/constants.py +++ b/mpas_analysis/shared/constants/constants.py @@ -1,14 +1,16 @@ +# 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 - -Authors -------- -Luke Van Roekel, Xylar Asay-Davis, Milena Veneziani - -Last modified -------------- -03/15/2017 """ +# Authors +# ------- +# Luke Van Roekel, Xylar Asay-Davis, Milena Veneziani from __future__ import absolute_import, division, print_function, \ unicode_literals @@ -64,4 +66,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 diff --git a/mpas_analysis/shared/containers.py b/mpas_analysis/shared/containers.py index a0b30f004..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 @@ -10,7 +17,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 +37,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..419e74a2b 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 @@ -7,11 +14,10 @@ open_multifile_dataset : opens a data set, maps variable names, preprocess the data set removes repeated time indices, and slices the time coordinate to lie between desired start and end dates. - -Authors -------- -Xylar Asay-Davis """ +# Authors +# ------- +# Xylar Asay-Davis from __future__ import absolute_import, division, print_function, \ unicode_literals @@ -21,8 +27,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, @@ -116,11 +123,10 @@ def open_multifile_dataset(fileNames, calendar, config, If the time variable is not found in the data set or if the time variable is a number of days since the start of the simulation but simulationStartTime is None. - - Authors - ------- - Xylar Asay-Davis, Phillip J. Wolfram """ + # Authors + # ------- + # Xylar Asay-Davis, Phillip J. Wolfram preprocess_partial = partial(_preprocess, calendar=calendar, @@ -270,11 +276,10 @@ def _preprocess(ds, calendar, simulationStartTime, timeVariableName, ds : xarray.DataSet object A copy of the data set with the time coordinate set and which has been sliced. - - Authors - ------- - Xylar Asay-Davis, Phillip J. Wolfram """ + # Authors + # ------- + # Xylar Asay-Davis, Phillip J. Wolfram submap = variableMap @@ -342,11 +347,11 @@ def _map_variable_name(variableName, ds, variableMap): # {{{ ValueError If none of the possible variable names in `variableMap[variableName]` can be found in `ds`. - - Authors - ------- - Xylar Asay-Davis """ + # Authors + # ------- + # Xylar Asay-Davis + possibleVariables = variableMap[variableName] for variable in possibleVariables: if isinstance(variable, (list, tuple)): @@ -390,11 +395,10 @@ def _rename_variables(ds, variableMap): # {{{ Returns ------- outDataSEt : A new `xarray.DataSet` object with the variable renamed. - - Authors - ------- - Xylar Asay-Davis """ + # Authors + # ------- + # Xylar Asay-Davis renameDict = {} for datasetVariable in ds.data_vars: 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/grid/grid.py b/mpas_analysis/shared/grid/grid.py index ba7c4096d..26fe38032 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 @@ -10,12 +17,10 @@ ProjectionGridDescriptor - describes a logically rectangular grid on a pyproj projection - -Authors -------- -Xylar Asay-Davis - ''' +# Authors +# ------- +# Xylar Asay-Davis from __future__ import absolute_import, division, print_function, \ unicode_literals @@ -30,23 +35,20 @@ class MeshDescriptor(object): # {{{ ''' A class for describing a mesh - - Authors - ------- - Xylar Asay-Davis ''' + # Authors + # ------- + # Xylar Asay-Davis def __init__(self): # {{{ ''' Constructor creates a common ``meshName`` member variable, ``None`` by default. Each Subclass should define or use input arguments to set ``meshName`` to a short description of the mesh or grid. - - Authors - ------- - Xylar Asay-Davis - ''' + # Authors + # ------- + # Xylar Asay-Davis self.meshName = None # }}} @@ -59,11 +61,10 @@ def to_scrip(self, scripFileName): # {{{ ---------- scripFileName : str The path to which the SCRIP file should be written - - Authors - ------ - Xylar Asay-Davis ''' + # Authors + # ------ + # Xylar Asay-Davis return # }}} @@ -73,11 +74,10 @@ def to_scrip(self, scripFileName): # {{{ class MpasMeshDescriptor(MeshDescriptor): # {{{ ''' A class for describing an MPAS mesh - - Authors - ------- - Xylar Asay-Davis ''' + # Authors + # ------- + # Xylar Asay-Davis def __init__(self, fileName, meshName=None): # {{{ ''' @@ -93,11 +93,10 @@ def __init__(self, fileName, meshName=None): # {{{ ``'oRRS18to6'``). If not provided, the data set in ``fileName`` must have a global attribute ``meshName`` that will be used instead. - - Authors - ------- - Xylar Asay-Davis ''' + # Authors + # ------- + # Xylar Asay-Davis ds = xarray.open_dataset(fileName) @@ -130,11 +129,11 @@ def to_scrip(self, scripFileName): # {{{ ---------- scripFileName : str The path to which the SCRIP file should be written - - Authors - ------- - Xylar Asay-Davis ''' + # Authors + # ------- + # Xylar Asay-Davis + self.scripFileName = scripFileName inFile = netCDF4.Dataset(self.fileName, 'r') @@ -195,11 +194,11 @@ def to_scrip(self, scripFileName): # {{{ class LatLonGridDescriptor(MeshDescriptor): # {{{ ''' A class for describing a lat-lon grid - - Authors - ------- - Xylar Asay-Davis ''' + # Authors + # ------- + # Xylar Asay-Davis + def __init__(self): # {{{ ''' Constructor stores the file name @@ -208,11 +207,11 @@ def __init__(self): # {{{ ---------- fileName : str The path of the file containing the MPAS mesh - - Authors - ------- - Xylar Asay-Davis ''' + # Authors + # ------- + # Xylar Asay-Davis + self.regional = False self.meshName = None # }}} @@ -234,11 +233,11 @@ def read(cls, fileName=None, ds=None, latVarName='lat', latVarName, lonVarName : str, optional The name of the latitude and longitude variables in the grid file - - Authors - ------- - Xylar Asay-Davis ''' + # Authors + # ------- + # Xylar Asay-Davis + if ds is None: ds = xarray.open_dataset(fileName) @@ -282,11 +281,11 @@ def create(cls, latCorner, lonCorner, units='degrees'): # {{{ units : {'degrees', 'radians'}, optional The units of `latCorner` and `lonCorner` - - Authors - ------- - Xylar Asay-Davis ''' + # Authors + # ------- + # Xylar Asay-Davis + descriptor = cls() descriptor.latCorner = latCorner @@ -306,11 +305,11 @@ def to_scrip(self, scripFileName): # {{{ ---------- scripFileName : str The path to which the SCRIP file should be written - - Authors - ------- - Xylar Asay-Davis ''' + # Authors + # ------- + # Xylar Asay-Davis + self.scripFileName = scripFileName outFile = netCDF4.Dataset(scripFileName, 'w') @@ -375,11 +374,10 @@ class ProjectionGridDescriptor(MeshDescriptor): # {{{ ''' A class for describing a general logically rectangular grid that can be defined by a `pyproj` projection. - - Authors - ------- - Xylar Asay-Davis ''' + # Authors + # ------- + # Xylar Asay-Davis def __init__(self, projection): # {{{ ''' @@ -390,11 +388,11 @@ def __init__(self, projection): # {{{ projection : ``pyproj.Proj`` object The projection used to map from grid x-y space to latitude and longitude - - Authors - ------- - Xylar Asay-Davis ''' + # Authors + # ------- + # Xylar Asay-Davis + self.projection = projection self.latLonProjection = pyproj.Proj(proj='latlong', datum='WGS84') self.regional = True @@ -423,11 +421,11 @@ def read(cls, projection, fileName, meshName=None, xVarName='x', xVarName, yVarName : str, optional The name of the x and y (in meters) variables in the grid file - - Authors - ------- - Xylar Asay-Davis ''' + # Authors + # ------- + # Xylar Asay-Davis + descriptor = cls(projection) ds = xarray.open_dataset(fileName) @@ -473,11 +471,11 @@ def create(cls, projection, x, y, meshName): # {{{ meshName : str The name of the grid (e.g. ``'10km_Antarctic_stereo'``) - - Authors - ------- - Xylar Asay-Davis ''' + # Authors + # ------- + # Xylar Asay-Davis + descriptor = cls(projection) descriptor.meshName = meshName @@ -501,11 +499,11 @@ def to_scrip(self, scripFileName): # {{{ ---------- scripFileName : str The path to which the SCRIP file should be written - - Authors - ------- - Xylar Asay-Davis ''' + # Authors + # ------- + # Xylar Asay-Davis + self.scripFileName = scripFileName outFile = netCDF4.Dataset(scripFileName, 'w') @@ -553,11 +551,10 @@ def project_to_lat_lon(self, X, Y): # {{{ ------- Lat, Lon : numpy.array with same shape as X and Y the latitude and longitude in degrees of the points - - Authors - ------- - Xylar Asay-Davis ''' + # Authors + # ------- + # Xylar Asay-Davis Lon, Lat = pyproj.transform(self.projection, self.latLonProjection, X, Y, radians=False) @@ -627,11 +624,11 @@ def _create_scrip(outFile, grid_size, grid_corners, grid_rank, units, meshName : str The name of the mesh - - Authors - ------- - Xylar Asay-Davis ''' + # Authors + # ------- + # Xylar Asay-Davis + # Write to output file # Dimensions outFile.createDimension("grid_size", grid_size) 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..b16c80a82 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 @@ -11,7 +18,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, @@ -74,11 +81,11 @@ def write_image_xml(config, filePrefix, componentName, componentSubdirectory, kwargs : dict additional keyword arguments will be used to add additional xml tags with the associated values - - Authors - ------- - Xylar Asay-Davis """ + # Authors + # ------- + # Xylar Asay-Davis + imageFileName = '{}.png'.format(filePrefix) plotsDirectory = build_config_full_path(config, 'output', 'plotsSubdirectory') @@ -141,11 +148,11 @@ def write_image_xml(config, filePrefix, componentName, componentSubdirectory, def _provenance_command(root, history): # {{{ """ Utility funciton for provenance of xml file associated with a plot. - - Authors - ------- - Xylar Asay-Davis """ + # Authors + # ------- + # Xylar Asay-Davis + call = ' '.join(sys.argv) if history is None: history = call diff --git a/mpas_analysis/shared/html/pages.py b/mpas_analysis/shared/html/pages.py index 7c3640228..ea9a7a03c 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 @@ -8,7 +15,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): # {{{ @@ -29,11 +36,11 @@ def generate_html(config, analyses, refConfig=None): # {{{ refConfig : ``MpasAnalysisConfigParser``, optional Config options for a reference run - - Authors - ------- - Xylar Asay-Davis """ + # Authors + # ------- + # Xylar Asay-Davis + generateHTML = config.getboolean('html', 'generate') if not generateHTML: return @@ -88,11 +95,11 @@ class MainPage(object): components : OrederdDict of dict Each component has a name, subdirectory and image name used to find the appropriate thumbnail. - - Authors - ------- - Xylar Asay-Davis """ + # Authors + # ------- + # Xylar Asay-Davis + def __init__(self, config, refConfig=None): """ Create a MainPage object, reading in the templates @@ -104,11 +111,10 @@ def __init__(self, config, refConfig=None): refConfig : ``MpasAnalysisConfigParser``, optional Config options for a reference run - - Authors - ------- - Xylar Asay-Davis """ + # Authors + # ------- + # Xylar Asay-Davis self.config = config self.refConfig = refConfig @@ -148,11 +154,11 @@ def add_component(self, name, subdirectory, imageFileName): The name of an image file (without path) that will be used as the thumbnail for the gallery. Typically, this is the first image from the first gallery. - - Authors - ------- - Xylar Asay-Davis """ + # Authors + # ------- + # Xylar Asay-Davis + self.components[name] = {'subdirectory': subdirectory, 'imageFileName': imageFileName} @@ -160,11 +166,11 @@ def generate(self): """ Generate the webpage from templates and components, and write it out to the HTML directory. - - Authors - ------- - Xylar Asay-Davis """ + # Authors + # ------- + # Xylar Asay-Davis + runName = self.config.get('runs', 'mainRunName') if self.refConfig is None: @@ -253,11 +259,11 @@ class ComponentPage(object): groups : tree of OrederdDict A tree of information describing the the gallery groups in the page, the galleries in each group and the images in each gallery. - - Authors - ------- - Xylar Asay-Davis """ + # Authors + # ------- + # Xylar Asay-Davis + def __init__(self, config, name, subdirectory, refConfig=None): """ Create a ComponentPage object, reading in the templates @@ -277,11 +283,10 @@ def __init__(self, config, name, subdirectory, refConfig=None): refConfig : ``MpasAnalysisConfigParser``, optional Config options for a reference run - - Authors - ------- - Xylar Asay-Davis """ + # Authors + # ------- + # Xylar Asay-Davis self.config = config self.refConfig = refConfig @@ -331,11 +336,11 @@ def add_image(xmlFileName, config, components, refConfig=None): refConfig : ``MpasAnalysisConfigParser``, optional Config options for a reference run - - Authors - ------- - Xylar Asay-Davis """ + # Authors + # ------- + # Xylar Asay-Davis + xmlRoot = etree.parse(xmlFileName).getroot() componentName = ComponentPage._get_required_xml_text(xmlRoot, @@ -398,11 +403,11 @@ def generate(self): """ Generate the webpage from templates and groups, and write it out to the HTML directory. - - Authors - ------- - Xylar Asay-Davis """ + # Authors + # ------- + # Xylar Asay-Davis + runName = self.config.get('runs', 'mainRunName') if self.refConfig is None: @@ -444,11 +449,11 @@ def get_first_image(self): ------- firstImageFilename : str The name (with out path) of the first image in the first gallery - - Authors - ------- - Xylar Asay-Davis """ + # Authors + # ------- + # Xylar Asay-Davis + # get the first image name firstGroup = next(iter(self.groups.values())) firstGallery = next(iter(firstGroup['galleries'].values())) 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